<!DOCTYPE html>
<html lang=zh>
<head>
    <meta charset="utf-8">
    
    <title>LErry</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
    <meta name="description" content="记录生活点滴">
<meta property="og:type" content="website">
<meta property="og:title" content="LErry">
<meta property="og:url" content="https://www.itchina.top/page/3/index.html">
<meta property="og:site_name" content="LErry">
<meta property="og:description" content="记录生活点滴">
<meta property="og:locale" content="zh-CN">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="LErry">
<meta name="twitter:description" content="记录生活点滴">
    

    
        <link rel="alternate" href="/atom.xml" title="LErry" type="application/atom+xml" />
    

    
        <link rel="icon" href="/css/images/shortcut_icon.png" />
    

    <link rel="stylesheet" href="/libs/font-awesome/css/font-awesome.min.css">
    <link rel="stylesheet" href="/libs/open-sans/styles.css">
    <link rel="stylesheet" href="/libs/source-code-pro/styles.css">

    <link rel="stylesheet" href="/css/style.css">

    <script src="/libs/jquery/2.1.3/jquery.min.js"></script>
    
    
        <link rel="stylesheet" href="/libs/lightgallery/css/lightgallery.min.css">
    
    
        <link rel="stylesheet" href="/libs/justified-gallery/justifiedGallery.min.css">
    
    
    
    


</head>

<body>
    <div id="container">
        <header id="header">
    <div id="header-main" class="header-inner">
        <div class="outer">
            <a href="/" id="logo">
                <i class="logo"></i>
                <span class="site-title">LErry</span>
            </a>
            <nav id="main-nav">
                
                    <a class="main-nav-link" href="/.">主页</a>
                
                    <a class="main-nav-link" href="/freebooks">书籍</a>
                
                    <a class="main-nav-link" href="/tags">标签</a>
                
                    <a class="main-nav-link" href="/archives">归档</a>
                
                    <a class="main-nav-link" href="/aboutme">关于</a>
                
            </nav>
            
                
                <nav id="sub-nav">
                    <div class="profile" id="profile-nav">
                        <a id="profile-anchor" href="javascript:;">
                            <img class="avatar" src="/css/images/avatar.png" />
                            <i class="fa fa-caret-down"></i>
                        </a>
                    </div>
                </nav>
            
            <div id="search-form-wrap">

    <form class="search-form">
        <input type="text" class="ins-search-input search-form-input" placeholder="搜索" />
        <button type="submit" class="search-form-submit"></button>
    </form>
    <div class="ins-search">
    <div class="ins-search-mask"></div>
    <div class="ins-search-container">
        <div class="ins-input-wrapper">
            <input type="text" class="ins-search-input" placeholder="想要查找什么..." />
            <span class="ins-close ins-selectable"><i class="fa fa-times-circle"></i></span>
        </div>
        <div class="ins-section-wrapper">
            <div class="ins-section-container"></div>
        </div>
    </div>
</div>
<script>
(function (window) {
    var INSIGHT_CONFIG = {
        TRANSLATION: {
            POSTS: '文章',
            PAGES: '页面',
            CATEGORIES: '分类',
            TAGS: '标签',
            UNTITLED: '(未命名)',
        },
        ROOT_URL: '/',
        CONTENT_URL: '/content.json',
    };
    window.INSIGHT_CONFIG = INSIGHT_CONFIG;
})(window);
</script>
<script src="/js/insight.js"></script>

</div>
        </div>
    </div>
    <div id="main-nav-mobile" class="header-sub header-inner">
        <table class="menu outer">
            <tr>
                
                    <td><a class="main-nav-link" href="/.">主页</a></td>
                
                    <td><a class="main-nav-link" href="/freebooks">书籍</a></td>
                
                    <td><a class="main-nav-link" href="/tags">标签</a></td>
                
                    <td><a class="main-nav-link" href="/archives">归档</a></td>
                
                    <td><a class="main-nav-link" href="/aboutme">关于</a></td>
                
                <td>
                    
    <div class="search-form">
        <input type="text" class="ins-search-input search-form-input" placeholder="搜索" />
    </div>

                </td>
            </tr>
        </table>
    </div>
</header>

        <div class="outer">
            
                

<aside id="profile">
    <div class="inner profile-inner">
        <div class="base-info profile-block">
            <img id="avatar" src="/css/images/avatar.png" />
            <h2 id="name">LErry Li</h2>
            <h3 id="title">知我者谓我心忧，不知我者谓我何求</h3>
            <span id="location"><i class="fa fa-map-marker"></i>Shanghai, China</span>
            <a id="follow" target="_blank" href="https://github.com/lerry903">关注我</a>
        </div>
        <div class="article-info profile-block">
            <div class="article-info-block">
                65
                <span>文章</span>
            </div>
            <div class="article-info-block">
                54
                <span>标签</span>
            </div>
        </div>
        
        <div class="profile-block social-links">
            <table>
                <tr>
                    
                    
                    <td>
                        <a href="https://github.com/lerry903" target="_blank" title="github" class=tooltip>
                            <i class="fa fa-github"></i>
                        </a>
                    </td>
                    
                    <td>
                        <a href="mailto:lerryli@foxmail.com" target="_blank" title="envelope" class=tooltip>
                            <i class="fa fa-envelope"></i>
                        </a>
                    </td>
                    
                    <td>
                        <a href="http://wpa.qq.com/msgrd?v=3&uin=824444270&site=qq&menu=yes" target="_blank" title="qq" class=tooltip>
                            <i class="fa fa-qq"></i>
                        </a>
                    </td>
                    
                    <td>
                        <a href="https://weibo.com/5941010376" target="_blank" title="weibo" class=tooltip>
                            <i class="fa fa-weibo"></i>
                        </a>
                    </td>
                    
                    <td>
                        <a href="/atom.xml" target="_blank" title="rss" class=tooltip>
                            <i class="fa fa-rss"></i>
                        </a>
                    </td>
                    
                </tr>
            </table>
        </div>
        
    </div>
</aside>

            
            <section id="main">
    <article id="post-Spring Boot 多数据源" class="article article-type-post" itemscope itemprop="blogPost">
    <div class="article-inner">
        
        
            <header class="article-header">
                
    
        <h1 itemprop="name">
            <a class="article-title" href="/2018/04/20/Spring Boot 多数据源/">Spring Boot 多数据源</a>
        </h1>
    

                
                    <div class="article-meta">
                        
    <div class="article-date">
        <i class="fa fa-calendar"></i>
        <a href="/2018/04/20/Spring Boot 多数据源/">
            <time datetime="2018-04-19T16:34:21.435Z" itemprop="datePublished">2018-04-20</time>
        </a>
    </div>


                        
    <div class="article-category">
    	<i class="fa fa-folder"></i>
        <a class="article-category-link" href="/categories/Spring/">Spring</a>
    </div>

                        
    <div class="article-tag">
        <i class="fa fa-tag"></i>
        <a class="tag-link" href="/tags/spring/">spring</a>
    </div>

                    </div>
                
            </header>
        
        
        <div class="article-entry" itemprop="articleBody">
        
            
            <p>上篇文章介绍了如何手工使用 <a href="http://lib.csdn.net/base/17" target="_blank" rel="noopener"> Java </a><br>代码将对象注册到Spring中，为本文“多数据源”做了基础。</p>
<p>下面一个Java类是我已经写好的根据配置文件动态创建多dataSource的代码，其原理也很简单，就是读取配置文件，根据配置文件中配置的数据源数量，动态创建<br>dataSource并注册到Spring中。<br>代码如下：</p>
<pre><code>package org.springboot.sample.config;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.AnnotationScopeMetadataResolver;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ScopeMetadata;
import org.springframework.context.annotation.ScopeMetadataResolver;
import org.springframework.core.env.Environment;

/**
 * 动态创建多数据源注册到Spring中
 *
 * @author 单红宇(365384722)
 * @myblog http://blog.csdn.net/catoop/
 * @create 2016年1月22日
 */
@Configuration
public class MultipleDataSourceBeanDefinitionRegistryPostProcessor
        implements BeanDefinitionRegistryPostProcessor, EnvironmentAware {

    private static final Logger logger = LoggerFactory
            .getLogger(MultipleDataSourceBeanDefinitionRegistryPostProcessor.class);

    // 如配置文件中未指定数据源类型，使用该默认值
    private static final Object DATASOURCE_TYPE_DEFAULT = &quot;org.apache.tomcat.jdbc.pool.DataSource&quot;;
//  private static final Object DATASOURCE_TYPE_DEFAULT = &quot;com.zaxxer.hikari.HikariDataSource&quot;;

    private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
    private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();

    // 存放DataSource配置的集合，模型&lt;dataSourceName,dataSourceMap&gt;
    private Map&lt;String, Map&lt;String, Object&gt;&gt; dataSourceMap = new HashMap&lt;&gt;();

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        logger.info(&quot;Invoke Metho postProcessBeanFactory&quot;);
        beanFactory.getBeanDefinition(&quot;dataSource&quot;).setPrimary(true);

        BeanDefinition bd = null;
        Map&lt;String, Object&gt; dsMap = null;
        for (Entry&lt;String, Map&lt;String, Object&gt;&gt; entry : dataSourceMap.entrySet()) {
            bd = beanFactory.getBeanDefinition(entry.getKey());
            MutablePropertyValues mpv = bd.getPropertyValues();
            dsMap = entry.getValue();
            mpv.addPropertyValue(&quot;driverClassName&quot;, dsMap.get(&quot;url&quot;));
            mpv.addPropertyValue(&quot;url&quot;, dsMap.get(&quot;url&quot;));
            mpv.addPropertyValue(&quot;username&quot;, dsMap.get(&quot;username&quot;));
            mpv.addPropertyValue(&quot;password&quot;, dsMap.get(&quot;password&quot;));
        }
    }

    @SuppressWarnings(&quot;unchecked&quot;)
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        logger.info(&quot;Invoke Metho postProcessBeanDefinitionRegistry&quot;);

        try {
            if(!dataSourceMap.isEmpty()){
                for (Entry&lt;String, Map&lt;String, Object&gt;&gt; entry : dataSourceMap.entrySet()) {

                    Object type = entry.getValue().get(&quot;type&quot;);
                    if(type == null)
                        type = DATASOURCE_TYPE_DEFAULT;// 默认DataSource
                    registerBean(registry, entry.getKey(), (Class&lt;? extends DataSource&gt;)Class.forName(type.toString()));
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }

    /**
     * 注册Bean到Spring
     *
     * @param registry
     * @param name
     * @param beanClass
     * @author SHANHY
     * @create 2016年1月22日
     */
    private void registerBean(BeanDefinitionRegistry registry, String name, Class&lt;?&gt; beanClass) {
        AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);

        ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
        abd.setScope(scopeMetadata.getScopeName());
        // 可以自动生成name
        String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, registry));

        AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);

        BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
        BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
    }

    /**
     * 加载多数据源配置
     */
    @Override
    public void setEnvironment(Environment env) {
        RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, &quot;custom.datasource.&quot;);
        String dsPrefixs = propertyResolver.getProperty(&quot;names&quot;);
        for (String dsPrefix : dsPrefixs.split(&quot;,&quot;)) {// 多个数据源
            Map&lt;String, Object&gt; dsMap = propertyResolver.getSubProperties(dsPrefix + &quot;.&quot;);
            dataSourceMap.put(dsPrefix, dsMap);
        }
    }
}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
<li>46 </li>
<li>47 </li>
<li>48 </li>
<li>49 </li>
<li>50 </li>
<li>51 </li>
<li>52 </li>
<li>53 </li>
<li>54 </li>
<li>55 </li>
<li>56 </li>
<li>57 </li>
<li>58 </li>
<li>59 </li>
<li>60 </li>
<li>61 </li>
<li>62 </li>
<li>63 </li>
<li>64 </li>
<li>65 </li>
<li>66 </li>
<li>67 </li>
<li>68 </li>
<li>69 </li>
<li>70 </li>
<li>71 </li>
<li>72 </li>
<li>73 </li>
<li>74 </li>
<li>75 </li>
<li>76 </li>
<li>77 </li>
<li>78 </li>
<li>79 </li>
<li>80 </li>
<li>81 </li>
<li>82 </li>
<li>83 </li>
<li>84 </li>
<li>85 </li>
<li>86 </li>
<li>87 </li>
<li>88 </li>
<li>89 </li>
<li>90 </li>
<li>91 </li>
<li>92 </li>
<li>93 </li>
<li>94 </li>
<li>95 </li>
<li>96 </li>
<li>97 </li>
<li>98 </li>
<li>99 </li>
<li>100 </li>
<li>101 </li>
<li>102 </li>
<li>103 </li>
<li>104 </li>
<li>105 </li>
<li>106 </li>
<li>107 </li>
<li>108 </li>
<li>109 </li>
<li>110 </li>
<li>111 </li>
<li>112 </li>
<li>113 </li>
<li>114 </li>
<li>115 </li>
<li>116 </li>
<li>117 </li>
<li>118 </li>
<li>119 </li>
<li>120 </li>
<li>121 </li>
<li>122 </li>
<li>123 </li>
<li>124 </li>
<li>125 </li>
<li>126 </li>
<li>127 </li>
<li>128 </li>
<li>129 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
<li>46 </li>
<li>47 </li>
<li>48 </li>
<li>49 </li>
<li>50 </li>
<li>51 </li>
<li>52 </li>
<li>53 </li>
<li>54 </li>
<li>55 </li>
<li>56 </li>
<li>57 </li>
<li>58 </li>
<li>59 </li>
<li>60 </li>
<li>61 </li>
<li>62 </li>
<li>63 </li>
<li>64 </li>
<li>65 </li>
<li>66 </li>
<li>67 </li>
<li>68 </li>
<li>69 </li>
<li>70 </li>
<li>71 </li>
<li>72 </li>
<li>73 </li>
<li>74 </li>
<li>75 </li>
<li>76 </li>
<li>77 </li>
<li>78 </li>
<li>79 </li>
<li>80 </li>
<li>81 </li>
<li>82 </li>
<li>83 </li>
<li>84 </li>
<li>85 </li>
<li>86 </li>
<li>87 </li>
<li>88 </li>
<li>89 </li>
<li>90 </li>
<li>91 </li>
<li>92 </li>
<li>93 </li>
<li>94 </li>
<li>95 </li>
<li>96 </li>
<li>97 </li>
<li>98 </li>
<li>99 </li>
<li>100 </li>
<li>101 </li>
<li>102 </li>
<li>103 </li>
<li>104 </li>
<li>105 </li>
<li>106 </li>
<li>107 </li>
<li>108 </li>
<li>109 </li>
<li>110 </li>
<li>111 </li>
<li>112 </li>
<li>113 </li>
<li>114 </li>
<li>115 </li>
<li>116 </li>
<li>117 </li>
<li>118 </li>
<li>119 </li>
<li>120 </li>
<li>121 </li>
<li>122 </li>
<li>123 </li>
<li>124 </li>
<li>125 </li>
<li>126 </li>
<li>127 </li>
<li>128 </li>
<li>129 </li>
</ul>
<p>将该Java文件直接添加到项目中便可，无其他任何代码耦合，就是单纯一个类。</p>
<hr>
<p>再来看一下在配置文件中配置多数据源的方法：</p>
<pre><code># 主数据源，默认的
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=123456

# 更多数据源
custom.datasource.names=ds1,ds2,ds3
custom.datasource.ds1.type=com.zaxxer.hikari.HikariDataSource
custom.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
custom.datasource.ds1.url=jdbc:mysql://localhost:3306/test
custom.datasource.ds1.username=root
custom.datasource.ds1.password=123456

custom.datasource.ds2.type=com.zaxxer.hikari.HikariDataSource
custom.datasource.ds2.driver-class-name=com.mysql.jdbc.Driver
custom.datasource.ds2.url=jdbc:mysql://localhost:3306/test
custom.datasource.ds2.username=root
custom.datasource.ds2.password=123456

custom.datasource.ds3.type=com.zaxxer.hikari.HikariDataSource
custom.datasource.ds3.driver-class-name=com.mysql.jdbc.Driver
custom.datasource.ds3.url=jdbc:mysql://localhost:3306/test
custom.datasource.ds3.username=root
custom.datasource.ds3.password=123456

# 下面为连接池的补充设置，应用到上面所有数据源中
spring.datasource.maximum-pool-size=100
spring.datasource.max-idle=10
spring.datasource.max-wait=10000
spring.datasource.min-idle=5
spring.datasource.initial-size=5
spring.datasource.validation-query=SELECT 1
spring.datasource.test-on-borrow=false
spring.datasource.test-while-idle=true
spring.datasource.time-between-eviction-runs-millis=18800
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
</ul>
<p>配置文件包括1个主数据源和多个数据源，其中主数据源在Spring中的beanName默认为dataSource，另外几个数据源的beanName分包为：ds<br>1、ds2、ds3，大家看一下配置的规则，想必不用多说。<br>其中datasource的type属性可以具体指定到我们需要的数据源上面，不指定情况下默认为：org.apache.tomcat.jdbc.pool.Dat<br>aSource</p>
<p>当然你也可以把这些数据源配置到主dataSource <a href="http://lib.csdn.net/base/14" target="_blank" rel="noopener"> 数据库 </a><br>中，然后读取数据库生成多数据源。当然这样做的必要性并不大，难不成数据源还会经常变吗。</p>
<hr>
<p>在需要应用dataSource的地方需要指定名称，如：</p>
<pre><code>// 方法参数注入方式
public void testDataSource(@Qualifier(&quot;ds1&quot;) DataSource myDataSource, @Qualifier(&quot;dataSource&quot;) DataSource dataSource) {

}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
</ul>
<p>或者</p>
<pre><code>// 类成员属性注入方式
@Autowired
@Qualifier(&quot;ds1&quot;)
private DataSource dataSource1;

@Resource(name = &quot;ds2&quot;)
private DataSource dataSource2;
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
</ul>
<p>本文共享的代码可以直接使用了，大家可以根据自己需要进行调整。</p>
<hr>
<p>然而我们在项目中不一定需要直接使用dataSource的，大家都习惯使用JDBC的jdbcTemplate、Mybatis的sqlSessionTempla<br>te，再或者就是以Mybatis为例直接动态代理到Mapper接口上。</p>
<p>那么如何做到完全动态数据源呢，以至于实现我们可以为同一个Java类的不同方法，分别指定使用不同的数据源？下篇文章将为大家揭晓。</p>

        
        </div>
        <footer class="article-footer">
            <div class="share-container">


    <div class="bdsharebuttonbox">
    <a href="#" class="bds_more" data-cmd="more">分享到：</a>
    <a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间">QQ空间</a>
    <a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博">新浪微博</a>
    <a href="#" class="bds_tqq" data-cmd="tqq" title="分享到腾讯微博">腾讯微博</a>
    <a href="#" class="bds_renren" data-cmd="renren" title="分享到人人网">人人网</a>
    <a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信">微信</a>
</div>
<script>
window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{"bdSize":16}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];
</script>
<style>
    .bdshare_popup_box {
        border-radius: 4px;
        border: #e1e1e1 solid 1px;
    }
    .bdshare-button-style0-16 a,
    .bdshare-button-style0-16 .bds_more {
        padding-left: 20px;
        margin: 6px 10px 6px 0;
    }
    .bdshare_dialog_list a,
    .bdshare_popup_list a,
    .bdshare_popup_bottom a {
        font-family: 'Microsoft Yahei';
    }
    .bdshare_popup_top {
        display: none;
    }
    .bdshare_popup_bottom {
        height: auto;
        padding: 5px;
    }
</style>


</div>

            
    
        <a href="https://www.itchina.top/2018/04/20/Spring Boot 多数据源/#comments" id="sourceId::2018/04/20/Spring Boot 多数据源/" class="article-comment-link cy_cmt_count">评论</a>
    

        </footer>
    </div>
    
</article>



    <article id="post-Spring Boot 部署与服务配置" class="article article-type-post" itemscope itemprop="blogPost">
    <div class="article-inner">
        
        
            <header class="article-header">
                
    
        <h1 itemprop="name">
            <a class="article-title" href="/2018/04/20/Spring Boot 部署与服务配置/">Spring Boot 部署与服务配置</a>
        </h1>
    

                
                    <div class="article-meta">
                        
    <div class="article-date">
        <i class="fa fa-calendar"></i>
        <a href="/2018/04/20/Spring Boot 部署与服务配置/">
            <time datetime="2018-04-19T16:34:21.434Z" itemprop="datePublished">2018-04-20</time>
        </a>
    </div>


                        
    <div class="article-category">
    	<i class="fa fa-folder"></i>
        <a class="article-category-link" href="/categories/Spring/">Spring</a>
    </div>

                        
    <div class="article-tag">
        <i class="fa fa-tag"></i>
        <a class="tag-link" href="/tags/spring/">spring</a>
    </div>

                    </div>
                
            </header>
        
        
        <div class="article-entry" itemprop="articleBody">
        
            
            <p>Spring Boot 其默认是集成web容器的，启动方式由像普通 <a href="http://lib.csdn.net/base/17" target="_blank" rel="noopener"> Java </a> 程序一样，m<br>ain函数入口启动。其内置Tomcat容器或Jetty容器，具体由配置来决定（默认Tomcat）。当然你也可以将项目打包成war包，放到独立的web容器中（<br>Tomcat、weblogic等等），当然在此之前你要对程序入口做简单调整。</p>
<p>项目构建我们使用Maven或Gradle，这将使项目依赖、jar包管理、以及打包部署变的非常方便。</p>
<h3 id="一、内嵌-Server-配置"><a href="#一、内嵌-Server-配置" class="headerlink" title="一、内嵌 Server 配置"></a>一、内嵌 Server 配置</h3><p>Spring Boot将容器内置后，它通过配置文件的方式类修改相关server配置。<br>先看一下下面的图，为关于server的配置列项：<br><img src="https://img-blog.csdn.net/20160126173131054" alt="配置"><br><img src="https://img-blog.csdn.net/20160126173159436" alt="配置"></p>
<p>其中常用的配置只有少数几个，已经用紫色标记起来。红框圈起来的部分，看名称分类就可以明白其作用。<br>对server的几个常用的配置做个简单说明：</p>
<pre><code># 项目contextPath，一般在正式发布版本中，我们不配置
server.context-path=/myspringboot
# 错误页，指定发生错误时，跳转的URL。请查看BasicErrorController源码便知
server.error.path=/error
# 服务端口
server.port=9090
# session最大超时时间(分钟)，默认为30
server.session-timeout=60
# 该服务绑定IP地址，启动服务器时如本机不是该IP地址则抛出异常启动失败，只有特殊需求的情况下才配置
# server.address=192.168.16.11
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
</ul>
<p><strong> Tomcat </strong><br>Tomcat为Spring Boot的默认容器，下面是几个常用配置：</p>
<pre><code># tomcat最大线程数，默认为200
server.tomcat.max-threads=800
# tomcat的URI编码
server.tomcat.uri-encoding=UTF-8
# 存放Tomcat的日志、Dump等文件的临时文件夹，默认为系统的tmp文件夹（如：C:\Users\Shanhy\AppData\Local\Temp）
server.tomcat.basedir=H:/springboot-tomcat-tmp
# 打开Tomcat的Access日志，并可以设置日志格式的方法：
#server.tomcat.access-log-enabled=true
#server.tomcat.access-log-pattern=
# accesslog目录，默认在basedir/logs
#server.tomcat.accesslog.directory=
# 日志文件目录
logging.path=H:/springboot-tomcat-tmp
# 日志文件名称，默认为spring.log
logging.file=myapp.log
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
</ul>
<p><strong> Jetty </strong><br>如果你要选择Jetty，也非常简单，就是把pom中的tomcat依赖排除，并加入Jetty容器的依赖，如下：</p>
<pre><code>&lt;dependencies&gt;
  &lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
    &lt;exclusions&gt;
      &lt;exclusion&gt;
        &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
        &lt;artifactId&gt;spring-boot-starter-tomcat&lt;/artifactId&gt;
      &lt;/exclusion&gt;
    &lt;/exclusions&gt;
  &lt;/dependency&gt;
  &lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-jetty&lt;/artifactId&gt;
  &lt;/dependency&gt;
&lt;dependencies&gt; 
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
</ul>
<p><strong> 打包 </strong><br>打包方法：<br>CMD进入项目目录，使用 mvn clean package 命令打包，以我的项目工程为例：</p>
<pre><code>E:\spring-boot-sample&gt;mvn clean package
</code></pre><ul>
<li>1 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
</ul>
<p>可以追加参数 -Dmaven.test.skip=true 跳过测试。<br>打包后的文件存放于项目下的target目录中，如：spring-boot-sample-0.0.1-SNAPSHOT.jar<br>如果pom配置的是war包，则为spring-boot-sample-0.0.1-SNAPSHOT.war</p>
<h3 id="二、部署到JavaEE容器"><a href="#二、部署到JavaEE容器" class="headerlink" title="二、部署到JavaEE容器"></a>二、部署到JavaEE容器</h3><ol>
<li>修改启动类，继承 SpringBootServletInitializer 并重写 configure 方法 </li>
</ol>
<pre><code>public class SpringBootSampleApplication extends SpringBootServletInitializer{

    private static final Logger logger = LoggerFactory.getLogger(SpringBootSampleApplication.class);

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(this.getClass());
    }

}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
</ul>
<ol>
<li>修改pom文件中jar 为 war </li>
</ol>
<pre><code>&lt;!-- &lt;packaging&gt;jar&lt;/packaging&gt; --&gt;
&lt;packaging&gt;war&lt;/packaging&gt;
</code></pre><ul>
<li>1 </li>
<li>2 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
</ul>
<ol>
<li>修改pom，排除tomcat插件 </li>
</ol>
<pre><code>&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;
    &lt;exclusions&gt;
        &lt;exclusion&gt;
            &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
            &lt;artifactId&gt;spring-boot-starter-tomcat&lt;/artifactId&gt;
        &lt;/exclusion&gt;
    &lt;/exclusions&gt;
&lt;/dependency&gt;
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
</ul>
<ol>
<li>打包部署到容器<br>使用命令 mvn clean package 打包后，同一般J2EE项目一样部署到web容器。</li>
</ol>
<h3 id="三、使用Profile区分环境"><a href="#三、使用Profile区分环境" class="headerlink" title="三、使用Profile区分环境"></a>三、使用Profile区分环境</h3><p>spring boot 可以在 “配置文件”、“Java代码类”、“日志配置” 中来配置profile区分不同环境执行不同的结果</p>
<p>1、配置文件<br>使用配置文件application.yml 和 application.properties 有所区别<br>以application.properties 为例，通过文件名来区分环境 application-{profile}.properties<br>application.properties</p>
<pre><code>app.name=MyApp
server.port=8080
spring.profiles.active=dev
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
</ul>
<p>application-dev.properties</p>
<pre><code>server.port=8081
</code></pre><ul>
<li>1 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
</ul>
<p>application-stg.properties</p>
<pre><code>server.port=8082
</code></pre><ul>
<li>1 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
</ul>
<p>在启动程序的时候通过添加 –spring.profiles.active={profile} 来指定具体使用的配置<br>例如我们执行 java -jar demo.jar –spring.profiles.active=dev 那么上面3个文件中的内容将被如何应用？<br>Spring Boot 会先加载默认的配置文件，然后使用具体指定的profile中的配置去覆盖默认配置。</p>
<blockquote>
<p>app.name 只存在于默认配置文件 application.properties 中，因为指定环境中不存在同样的配置，所以该值不会被覆盖<br>server.port 默认为8080，但是我们指定了环境后，将会被覆盖。如果指定stg环境，server.port 则为 8082<br>spring.profiles.active 默认指定dev环境，如果我们在运行时指定 –spring.profiles.active=stg<br>那么将应用stg环境，最终 server.port 的值为8082</p>
</blockquote>
<p>2、Java类中@Profile注解<br>下面2个不同的类实现了同一个接口，@Profile注解指定了具体环境</p>
<pre><code>// 接口定义
public interface SendMessage {

    // 发送短信方法定义
    public void send();

}

// Dev 环境实现类
@Component
@Profile(&quot;dev&quot;)
public class DevSendMessage implements SendMessage {

    @Override
    public void send() {
        System.out.println(&quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;Dev Send()&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&quot;);
    }

}

// Stg环境实现类
@Component
@Profile(&quot;stg&quot;)
public class StgSendMessage implements SendMessage {

    @Override
    public void send() {
        System.out.println(&quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;Stg Send()&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&quot;);
    }

}

// 启动类
@SpringBootApplication
public class ProfiledemoApplication {

    @Value(&quot;${app.name}&quot;)
    private String name;

    @Autowired
    private SendMessage sendMessage;

    @PostConstruct
    public void init(){
        sendMessage.send();// 会根据profile指定的环境实例化对应的类
    }

}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
<li>46 </li>
<li>47 </li>
<li>48 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
<li>46 </li>
<li>47 </li>
<li>48 </li>
</ul>
<p>3、logback-spring.xml也支持有节点来支持区分</p>
<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;configuration&gt;
    &lt;include resource=&quot;org/springframework/boot/logging/logback/base.xml&quot; /&gt;
    &lt;logger name=&quot;org.springframework.web&quot; level=&quot;INFO&quot;/&gt;

    &lt;springProfile name=&quot;default&quot;&gt;
        &lt;logger name=&quot;org.springboot.sample&quot; level=&quot;TRACE&quot; /&gt;
    &lt;/springProfile&gt;

    &lt;springProfile name=&quot;dev&quot;&gt;
        &lt;logger name=&quot;org.springboot.sample&quot; level=&quot;DEBUG&quot; /&gt;
    &lt;/springProfile&gt;

    &lt;springProfile name=&quot;staging&quot;&gt;
        &lt;logger name=&quot;org.springboot.sample&quot; level=&quot;INFO&quot; /&gt;
    &lt;/springProfile&gt;

&lt;/configuration&gt;
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
</ul>
<p>再说一遍文件名不要用logback.xml 请使用logback-spring.xml</p>
<h3 id="四、指定外部的配置文件"><a href="#四、指定外部的配置文件" class="headerlink" title="四、指定外部的配置文件"></a>四、指定外部的配置文件</h3><p>有些系统，关于一些 <a href="http://lib.csdn.net/base/14" target="_blank" rel="noopener"> 数据库 </a><br>或其他第三方账户等信息，由于安全问题，其配置并不会提前配置在项目中暴露给开发人员。<br>对于这种情况，我们在运行程序的时候，可以通过参数指定一个外部配置文件。<br>以 demo.jar 为例，方法如下：</p>
<pre><code>java -jar demo.jar --spring.config.location=/opt/config/application.properties
</code></pre><ul>
<li>1 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
</ul>
<p>其中文件名随便定义，无固定要求。</p>
<h3 id="五、创建一个Linux-应用的sh脚本"><a href="#五、创建一个Linux-应用的sh脚本" class="headerlink" title="五、创建一个Linux 应用的sh脚本"></a>五、创建一个Linux 应用的sh脚本</h3><p>下面几个脚本仅供参考，请根据自己需要做调整<br>start.sh</p>
<pre><code>#!/bin/sh

rm -f tpid

nohup java -jar myapp.jar --spring.config.location=application.yml &gt; /dev/null 2&gt;&amp;1 &amp;

echo $! &gt; tpid

echo Start Success!
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
</ul>
<p>stop.sh</p>
<pre><code>#!/bin/sh
APP_NAME=myapp

tpid=`ps -ef|grep $APP_NAME|grep -v grep|grep -v kill|awk &apos;{print $2}&apos;`
if [ ${tpid} ]; then
    echo &apos;Stop Process...&apos;
    kill -15 $tpid
fi
sleep 5
tpid=`ps -ef|grep $APP_NAME|grep -v grep|grep -v kill|awk &apos;{print $2}&apos;`
if [ ${tpid} ]; then
    echo &apos;Kill Process!&apos;
    kill -9 $tpid
else
    echo &apos;Stop Success!&apos;
fi
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
</ul>
<p>check.sh</p>
<pre><code>#!/bin/sh
APP_NAME=myapp

tpid=`ps -ef|grep $APP_NAME|grep -v grep|grep -v kill|awk &apos;{print $2}&apos;`
if [ ${tpid} ]; then
        echo &apos;App is running.&apos;
else
        echo &apos;App is NOT running.&apos;
fi
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
</ul>
<p>kill.sh</p>
<pre><code>#!/bin/sh
APP_NAME=myapp

tpid=`ps -ef|grep $APP_NAME|grep -v grep|grep -v kill|awk &apos;{print $2}&apos;`
if [ ${tpid} ]; then
    echo &apos;Kill Process!&apos;
    kill -9 $tpid
fi
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
</ul>

        
        </div>
        <footer class="article-footer">
            <div class="share-container">


    <div class="bdsharebuttonbox">
    <a href="#" class="bds_more" data-cmd="more">分享到：</a>
    <a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间">QQ空间</a>
    <a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博">新浪微博</a>
    <a href="#" class="bds_tqq" data-cmd="tqq" title="分享到腾讯微博">腾讯微博</a>
    <a href="#" class="bds_renren" data-cmd="renren" title="分享到人人网">人人网</a>
    <a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信">微信</a>
</div>
<script>
window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{"bdSize":16}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];
</script>
<style>
    .bdshare_popup_box {
        border-radius: 4px;
        border: #e1e1e1 solid 1px;
    }
    .bdshare-button-style0-16 a,
    .bdshare-button-style0-16 .bds_more {
        padding-left: 20px;
        margin: 6px 10px 6px 0;
    }
    .bdshare_dialog_list a,
    .bdshare_popup_list a,
    .bdshare_popup_bottom a {
        font-family: 'Microsoft Yahei';
    }
    .bdshare_popup_top {
        display: none;
    }
    .bdshare_popup_bottom {
        height: auto;
        padding: 5px;
    }
</style>


</div>

            
    
        <a href="https://www.itchina.top/2018/04/20/Spring Boot 部署与服务配置/#comments" id="sourceId::2018/04/20/Spring Boot 部署与服务配置/" class="article-comment-link cy_cmt_count">评论</a>
    

        </footer>
    </div>
    
</article>



    <article id="post-Spring Boot 动态数据源（多数据源自动切换）" class="article article-type-post" itemscope itemprop="blogPost">
    <div class="article-inner">
        
        
            <header class="article-header">
                
    
        <h1 itemprop="name">
            <a class="article-title" href="/2018/04/20/Spring Boot 动态数据源（多数据源自动切换）/">Spring Boot 动态数据源（多数据源自动切换）</a>
        </h1>
    

                
                    <div class="article-meta">
                        
    <div class="article-date">
        <i class="fa fa-calendar"></i>
        <a href="/2018/04/20/Spring Boot 动态数据源（多数据源自动切换）/">
            <time datetime="2018-04-19T16:34:21.434Z" itemprop="datePublished">2018-04-20</time>
        </a>
    </div>


                        
    <div class="article-category">
    	<i class="fa fa-folder"></i>
        <a class="article-category-link" href="/categories/Spring/">Spring</a>
    </div>

                        
    <div class="article-tag">
        <i class="fa fa-tag"></i>
        <a class="tag-link" href="/tags/spring/">spring</a>
    </div>

                    </div>
                
            </header>
        
        
        <div class="article-entry" itemprop="articleBody">
        
            
            <p>本文实现案例场景：<br>某系统除了需要从自己的主要 <a href="http://lib.csdn.net/base/14" target="_blank" rel="noopener"> 数据库 </a><br>上读取和管理数据外，还有一部分业务涉及到其他多个数据库，要求可以在任何方法上可以灵活指定具体要操作的数据库。</p>
<p>为了在开发中以最简单的方法使用，本文基于注解和AOP的方法实现，在spring<br>boot框架的项目中，添加本文实现的代码类后，只需要配置好数据源就可以直接通过注解使用，简单方便。</p>
<p><strong> 一配置二使用 </strong><br><strong> 1. 启动类注册动态数据源 </strong><br><strong> 2. 配置文件中配置多个数据源 </strong><br><strong> 3. 在需要的方法上使用注解指定数据源 </strong></p>
<p>1、在启动类添加 @Import({DynamicDataSourceRegister.class,<br>MProxyTransactionManagementConfiguration.class})</p>
<pre><code>@SpringBootApplication
@Import({DynamicDataSourceRegister.class}) // 注册动态多数据源
public class SpringBootSampleApplication {

    // 省略其他代码
}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
</ul>
<p>2、配置文件配置内容为：<br>（不包括项目中的其他配置，这里只是数据源相关的）</p>
<pre><code># 主数据源，默认的
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=123456

# 更多数据源
custom.datasource.names=ds1,ds2
custom.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver
custom.datasource.ds1.url=jdbc:mysql://localhost:3306/test1
custom.datasource.ds1.username=root
custom.datasource.ds1.password=123456

custom.datasource.ds2.driver-class-name=com.mysql.jdbc.Driver
custom.datasource.ds2.url=jdbc:mysql://localhost:3306/test2
custom.datasource.ds2.username=root
custom.datasource.ds2.password=123456
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
</ul>
<p>3、使用方法</p>
<pre><code>package org.springboot.sample.service;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import org.springboot.sample.datasource.TargetDataSource;
import org.springboot.sample.entity.Student;
import org.springboot.sample.mapper.StudentMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;

/**
 * Student Service
 *
 * @author   单红宇(365384722)
 * @myblog  http://blog.csdn.net/catoop/
 * @create    2016年1月12日
 */
@Service
public class StudentService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    // MyBatis的Mapper方法定义接口
    @Autowired
    private StudentMapper studentMapper;

    @TargetDataSource(name=&quot;ds2&quot;)
    public List&lt;Student&gt; likeName(String name){
        return studentMapper.likeName(name);
    }

    public List&lt;Student&gt; likeNameByDefaultDataSource(String name){
        return studentMapper.likeName(name);
    }

    /**
     * 不指定数据源使用默认数据源
     *
     * @return
     * @author SHANHY
     * @create  2016年1月24日
     */
    public List&lt;Student&gt; getList(){
        String sql = &quot;SELECT ID,NAME,SCORE_SUM,SCORE_AVG, AGE   FROM STUDENT&quot;;
        return (List&lt;Student&gt;) jdbcTemplate.query(sql, new RowMapper&lt;Student&gt;(){

            @Override
            public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
                Student stu = new Student();
                stu.setId(rs.getInt(&quot;ID&quot;));
                stu.setAge(rs.getInt(&quot;AGE&quot;));
                stu.setName(rs.getString(&quot;NAME&quot;));
                stu.setSumScore(rs.getString(&quot;SCORE_SUM&quot;));
                stu.setAvgScore(rs.getString(&quot;SCORE_AVG&quot;));
                return stu;
            }

        });
    }

    /**
     * 指定数据源
     *
     * @return
     * @author SHANHY
     * @create  2016年1月24日
     */
    @TargetDataSource(name=&quot;ds1&quot;)
    public List&lt;Student&gt; getListByDs1(){
        String sql = &quot;SELECT ID,NAME,SCORE_SUM,SCORE_AVG, AGE   FROM STUDENT&quot;;
        return (List&lt;Student&gt;) jdbcTemplate.query(sql, new RowMapper&lt;Student&gt;(){

            @Override
            public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
                Student stu = new Student();
                stu.setId(rs.getInt(&quot;ID&quot;));
                stu.setAge(rs.getInt(&quot;AGE&quot;));
                stu.setName(rs.getString(&quot;NAME&quot;));
                stu.setSumScore(rs.getString(&quot;SCORE_SUM&quot;));
                stu.setAvgScore(rs.getString(&quot;SCORE_AVG&quot;));
                return stu;
            }

        });
    }

    /**
     * 指定数据源
     *
     * @return
     * @author SHANHY
     * @create  2016年1月24日
     */
    @TargetDataSource(name=&quot;ds2&quot;)
    public List&lt;Student&gt; getListByDs2(){
        String sql = &quot;SELECT ID,NAME,SCORE_SUM,SCORE_AVG, AGE   FROM STUDENT&quot;;
        return (List&lt;Student&gt;) jdbcTemplate.query(sql, new RowMapper&lt;Student&gt;(){

            @Override
            public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
                Student stu = new Student();
                stu.setId(rs.getInt(&quot;ID&quot;));
                stu.setAge(rs.getInt(&quot;AGE&quot;));
                stu.setName(rs.getString(&quot;NAME&quot;));
                stu.setSumScore(rs.getString(&quot;SCORE_SUM&quot;));
                stu.setAvgScore(rs.getString(&quot;SCORE_AVG&quot;));
                return stu;
            }

        });
    }
}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
<li>46 </li>
<li>47 </li>
<li>48 </li>
<li>49 </li>
<li>50 </li>
<li>51 </li>
<li>52 </li>
<li>53 </li>
<li>54 </li>
<li>55 </li>
<li>56 </li>
<li>57 </li>
<li>58 </li>
<li>59 </li>
<li>60 </li>
<li>61 </li>
<li>62 </li>
<li>63 </li>
<li>64 </li>
<li>65 </li>
<li>66 </li>
<li>67 </li>
<li>68 </li>
<li>69 </li>
<li>70 </li>
<li>71 </li>
<li>72 </li>
<li>73 </li>
<li>74 </li>
<li>75 </li>
<li>76 </li>
<li>77 </li>
<li>78 </li>
<li>79 </li>
<li>80 </li>
<li>81 </li>
<li>82 </li>
<li>83 </li>
<li>84 </li>
<li>85 </li>
<li>86 </li>
<li>87 </li>
<li>88 </li>
<li>89 </li>
<li>90 </li>
<li>91 </li>
<li>92 </li>
<li>93 </li>
<li>94 </li>
<li>95 </li>
<li>96 </li>
<li>97 </li>
<li>98 </li>
<li>99 </li>
<li>100 </li>
<li>101 </li>
<li>102 </li>
<li>103 </li>
<li>104 </li>
<li>105 </li>
<li>106 </li>
<li>107 </li>
<li>108 </li>
<li>109 </li>
<li>110 </li>
<li>111 </li>
<li>112 </li>
<li>113 </li>
<li>114 </li>
<li>115 </li>
<li>116 </li>
<li>117 </li>
<li>118 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
<li>46 </li>
<li>47 </li>
<li>48 </li>
<li>49 </li>
<li>50 </li>
<li>51 </li>
<li>52 </li>
<li>53 </li>
<li>54 </li>
<li>55 </li>
<li>56 </li>
<li>57 </li>
<li>58 </li>
<li>59 </li>
<li>60 </li>
<li>61 </li>
<li>62 </li>
<li>63 </li>
<li>64 </li>
<li>65 </li>
<li>66 </li>
<li>67 </li>
<li>68 </li>
<li>69 </li>
<li>70 </li>
<li>71 </li>
<li>72 </li>
<li>73 </li>
<li>74 </li>
<li>75 </li>
<li>76 </li>
<li>77 </li>
<li>78 </li>
<li>79 </li>
<li>80 </li>
<li>81 </li>
<li>82 </li>
<li>83 </li>
<li>84 </li>
<li>85 </li>
<li>86 </li>
<li>87 </li>
<li>88 </li>
<li>89 </li>
<li>90 </li>
<li>91 </li>
<li>92 </li>
<li>93 </li>
<li>94 </li>
<li>95 </li>
<li>96 </li>
<li>97 </li>
<li>98 </li>
<li>99 </li>
<li>100 </li>
<li>101 </li>
<li>102 </li>
<li>103 </li>
<li>104 </li>
<li>105 </li>
<li>106 </li>
<li>107 </li>
<li>108 </li>
<li>109 </li>
<li>110 </li>
<li>111 </li>
<li>112 </li>
<li>113 </li>
<li>114 </li>
<li>115 </li>
<li>116 </li>
<li>117 </li>
<li>118 </li>
</ul>
<p>要注意的是，在使用MyBatis时，注解@TargetDataSource 不能直接在接口类Mapper上使用。<br>按上面的代码中StudentMapper为接口，代码如下：</p>
<pre><code>package org.springboot.sample.mapper;

import java.util.List;

import org.springboot.sample.entity.Student;

/**
 * StudentMapper，映射SQL语句的接口，无逻辑实现
 *
 * @author 单红宇(365384722)
 * @myblog http://blog.csdn.net/catoop/
 * @create 2016年1月20日
 */
public interface StudentMapper {

    // 注解 @TargetDataSource 不可以在这里使用
    List&lt;Student&gt; likeName(String name);

    Student getById(int id);

    String getNameById(int id);

}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
</ul>
<hr>
<hr>
<p>请将下面几个类放到Spring Boot项目中。<br>DynamicDataSource. <a href="http://lib.csdn.net/base/17" target="_blank" rel="noopener"> Java </a><br>DynamicDataSourceAspect.java<br>DynamicDataSourceContextHolder.java<br>DynamicDataSourceRegister.java<br>TargetDataSource.java</p>
<pre><code>package org.springboot.sample.datasource;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**
 * 动态数据源
 *
 * @author   单红宇(365384722)
 * @myblog  http://blog.csdn.net/catoop/
 * @create    2016年1月22日
 */
public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceContextHolder.getDataSourceType();
    }

}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
</ul>
<pre><code>package org.springboot.sample.datasource;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * 切换数据源Advice
 *
 * @author 单红宇(365384722)
 * @myblog http://blog.csdn.net/catoop/
 * @create 2016年1月23日
 */
@Aspect
@Order(-1)// 保证该AOP在@Transactional之前执行
@Component
public class DynamicDataSourceAspect {

    private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceAspect.class);

    @Before(&quot;@annotation(ds)&quot;)
    public void changeDataSource(JoinPoint point, TargetDataSource ds) throws Throwable {
        String dsId = ds.name();
        if (!DynamicDataSourceContextHolder.containsDataSource(dsId)) {
            logger.error(&quot;数据源[{}]不存在，使用默认数据源 &gt; {}&quot;, ds.name(), point.getSignature());
        } else {
            logger.debug(&quot;Use DataSource : {} &gt; {}&quot;, ds.name(), point.getSignature());
            DynamicDataSourceContextHolder.setDataSourceType(ds.name());
        }
    }

    @After(&quot;@annotation(ds)&quot;)
    public void restoreDataSource(JoinPoint point, TargetDataSource ds) {
        logger.debug(&quot;Revert DataSource : {} &gt; {}&quot;, ds.name(), point.getSignature());
        DynamicDataSourceContextHolder.clearDataSourceType();
    }

}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
</ul>
<pre><code>package org.springboot.sample.datasource;

import java.util.ArrayList;
import java.util.List;

public class DynamicDataSourceContextHolder {

    private static final ThreadLocal&lt;String&gt; contextHolder = new ThreadLocal&lt;String&gt;();
    public static List&lt;String&gt; dataSourceIds = new ArrayList&lt;&gt;();

    public static void setDataSourceType(String dataSourceType) {
        contextHolder.set(dataSourceType);
    }

    public static String getDataSourceType() {
        return contextHolder.get();
    }

    public static void clearDataSourceType() {
        contextHolder.remove();
    }

    /**
     * 判断指定DataSrouce当前是否存在
     *
     * @param dataSourceId
     * @return
     * @author SHANHY
     * @create  2016年1月24日
     */
    public static boolean containsDataSource(String dataSourceId){
        return dataSourceIds.contains(dataSourceId);
    }
}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
</ul>
<pre><code>package org.springboot.sample.datasource;

import java.util.HashMap;
import java.util.Map;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.bind.RelaxedDataBinder;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;

/**
 * 动态数据源注册&lt;br/&gt;
 * 启动动态数据源请在启动类中（如SpringBootSampleApplication）
 * 添加 @Import(DynamicDataSourceRegister.class)
 *
 * @author 单红宇(365384722)
 * @myblog http://blog.csdn.net/catoop/
 * @create 2016年1月24日
 */
public class DynamicDataSourceRegister
        implements ImportBeanDefinitionRegistrar, EnvironmentAware {

    private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceRegister.class);

    private ConversionService conversionService = new DefaultConversionService(); 
    private PropertyValues dataSourcePropertyValues;

    // 如配置文件中未指定数据源类型，使用该默认值
    private static final Object DATASOURCE_TYPE_DEFAULT = &quot;org.apache.tomcat.jdbc.pool.DataSource&quot;;
    // private static final Object DATASOURCE_TYPE_DEFAULT =
    // &quot;com.zaxxer.hikari.HikariDataSource&quot;;

    // 数据源
    private DataSource defaultDataSource;
    private Map&lt;String, DataSource&gt; customDataSources = new HashMap&lt;&gt;();

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        Map&lt;Object, Object&gt; targetDataSources = new HashMap&lt;Object, Object&gt;();
        // 将主数据源添加到更多数据源中
        targetDataSources.put(&quot;dataSource&quot;, defaultDataSource);
        DynamicDataSourceContextHolder.dataSourceIds.add(&quot;dataSource&quot;);
        // 添加更多数据源
        targetDataSources.putAll(customDataSources);
        for (String key : customDataSources.keySet()) {
            DynamicDataSourceContextHolder.dataSourceIds.add(key);
        }

        // 创建DynamicDataSource
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClass(DynamicDataSource.class);
        beanDefinition.setSynthetic(true);
        MutablePropertyValues mpv = beanDefinition.getPropertyValues();
        mpv.addPropertyValue(&quot;defaultTargetDataSource&quot;, defaultDataSource);
        mpv.addPropertyValue(&quot;targetDataSources&quot;, targetDataSources);
        registry.registerBeanDefinition(&quot;dataSource&quot;, beanDefinition);

        logger.info(&quot;Dynamic DataSource Registry&quot;);
    }

    /**
     * 创建DataSource
     *
     * @param type
     * @param driverClassName
     * @param url
     * @param username
     * @param password
     * @return
     * @author SHANHY
     * @create 2016年1月24日
     */
    @SuppressWarnings(&quot;unchecked&quot;)
    public DataSource buildDataSource(Map&lt;String, Object&gt; dsMap) {
        try {
            Object type = dsMap.get(&quot;type&quot;);
            if (type == null)
                type = DATASOURCE_TYPE_DEFAULT;// 默认DataSource

            Class&lt;? extends DataSource&gt; dataSourceType;
            dataSourceType = (Class&lt;? extends DataSource&gt;) Class.forName((String) type);

            String driverClassName = dsMap.get(&quot;driver-class-name&quot;).toString();
            String url = dsMap.get(&quot;url&quot;).toString();
            String username = dsMap.get(&quot;username&quot;).toString();
            String password = dsMap.get(&quot;password&quot;).toString();

            DataSourceBuilder factory = DataSourceBuilder.create().driverClassName(driverClassName).url(url)
                    .username(username).password(password).type(dataSourceType);
            return factory.build();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 加载多数据源配置
     */
    @Override
    public void setEnvironment(Environment env) {
        initDefaultDataSource(env);
        initCustomDataSources(env);
    }

    /**
     * 初始化主数据源
     *
     * @author SHANHY
     * @create 2016年1月24日
     */
    private void initDefaultDataSource(Environment env) {
        // 读取主数据源
        RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, &quot;spring.datasource.&quot;);
        Map&lt;String, Object&gt; dsMap = new HashMap&lt;&gt;();
        dsMap.put(&quot;type&quot;, propertyResolver.getProperty(&quot;type&quot;));
        dsMap.put(&quot;driver-class-name&quot;, propertyResolver.getProperty(&quot;driver-class-name&quot;));
        dsMap.put(&quot;url&quot;, propertyResolver.getProperty(&quot;url&quot;));
        dsMap.put(&quot;username&quot;, propertyResolver.getProperty(&quot;username&quot;));
        dsMap.put(&quot;password&quot;, propertyResolver.getProperty(&quot;password&quot;));

        defaultDataSource = buildDataSource(dsMap);

        dataBinder(defaultDataSource, env);
    }

    /**
     * 为DataSource绑定更多数据
     *
     * @param dataSource
     * @param env
     * @author SHANHY
     * @create  2016年1月25日
     */
    private void dataBinder(DataSource dataSource, Environment env){
        RelaxedDataBinder dataBinder = new RelaxedDataBinder(dataSource);
        //dataBinder.setValidator(new LocalValidatorFactory().run(this.applicationContext));
        dataBinder.setConversionService(conversionService);
        dataBinder.setIgnoreNestedProperties(false);//false
        dataBinder.setIgnoreInvalidFields(false);//false
        dataBinder.setIgnoreUnknownFields(true);//true
        if(dataSourcePropertyValues == null){
            Map&lt;String, Object&gt; rpr = new RelaxedPropertyResolver(env, &quot;spring.datasource&quot;).getSubProperties(&quot;.&quot;);
            Map&lt;String, Object&gt; values = new HashMap&lt;&gt;(rpr);
            // 排除已经设置的属性
            values.remove(&quot;type&quot;);
            values.remove(&quot;driver-class-name&quot;);
            values.remove(&quot;url&quot;);
            values.remove(&quot;username&quot;);
            values.remove(&quot;password&quot;);
            dataSourcePropertyValues = new MutablePropertyValues(values);
        }
        dataBinder.bind(dataSourcePropertyValues);
    }

    /**
     * 初始化更多数据源
     *
     * @author SHANHY
     * @create 2016年1月24日
     */
    private void initCustomDataSources(Environment env) {
        // 读取配置文件获取更多数据源，也可以通过defaultDataSource读取数据库获取更多数据源
        RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(env, &quot;custom.datasource.&quot;);
        String dsPrefixs = propertyResolver.getProperty(&quot;names&quot;);
        for (String dsPrefix : dsPrefixs.split(&quot;,&quot;)) {// 多个数据源
            Map&lt;String, Object&gt; dsMap = propertyResolver.getSubProperties(dsPrefix + &quot;.&quot;);
            DataSource ds = buildDataSource(dsMap);
            customDataSources.put(dsPrefix, ds);
            dataBinder(ds, env);
        }
    }

}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
<li>46 </li>
<li>47 </li>
<li>48 </li>
<li>49 </li>
<li>50 </li>
<li>51 </li>
<li>52 </li>
<li>53 </li>
<li>54 </li>
<li>55 </li>
<li>56 </li>
<li>57 </li>
<li>58 </li>
<li>59 </li>
<li>60 </li>
<li>61 </li>
<li>62 </li>
<li>63 </li>
<li>64 </li>
<li>65 </li>
<li>66 </li>
<li>67 </li>
<li>68 </li>
<li>69 </li>
<li>70 </li>
<li>71 </li>
<li>72 </li>
<li>73 </li>
<li>74 </li>
<li>75 </li>
<li>76 </li>
<li>77 </li>
<li>78 </li>
<li>79 </li>
<li>80 </li>
<li>81 </li>
<li>82 </li>
<li>83 </li>
<li>84 </li>
<li>85 </li>
<li>86 </li>
<li>87 </li>
<li>88 </li>
<li>89 </li>
<li>90 </li>
<li>91 </li>
<li>92 </li>
<li>93 </li>
<li>94 </li>
<li>95 </li>
<li>96 </li>
<li>97 </li>
<li>98 </li>
<li>99 </li>
<li>100 </li>
<li>101 </li>
<li>102 </li>
<li>103 </li>
<li>104 </li>
<li>105 </li>
<li>106 </li>
<li>107 </li>
<li>108 </li>
<li>109 </li>
<li>110 </li>
<li>111 </li>
<li>112 </li>
<li>113 </li>
<li>114 </li>
<li>115 </li>
<li>116 </li>
<li>117 </li>
<li>118 </li>
<li>119 </li>
<li>120 </li>
<li>121 </li>
<li>122 </li>
<li>123 </li>
<li>124 </li>
<li>125 </li>
<li>126 </li>
<li>127 </li>
<li>128 </li>
<li>129 </li>
<li>130 </li>
<li>131 </li>
<li>132 </li>
<li>133 </li>
<li>134 </li>
<li>135 </li>
<li>136 </li>
<li>137 </li>
<li>138 </li>
<li>139 </li>
<li>140 </li>
<li>141 </li>
<li>142 </li>
<li>143 </li>
<li>144 </li>
<li>145 </li>
<li>146 </li>
<li>147 </li>
<li>148 </li>
<li>149 </li>
<li>150 </li>
<li>151 </li>
<li>152 </li>
<li>153 </li>
<li>154 </li>
<li>155 </li>
<li>156 </li>
<li>157 </li>
<li>158 </li>
<li>159 </li>
<li>160 </li>
<li>161 </li>
<li>162 </li>
<li>163 </li>
<li>164 </li>
<li>165 </li>
<li>166 </li>
<li>167 </li>
<li>168 </li>
<li>169 </li>
<li>170 </li>
<li>171 </li>
<li>172 </li>
<li>173 </li>
<li>174 </li>
<li>175 </li>
<li>176 </li>
<li>177 </li>
<li>178 </li>
<li>179 </li>
<li>180 </li>
<li>181 </li>
<li>182 </li>
<li>183 </li>
<li>184 </li>
<li>185 </li>
<li>186 </li>
<li>187 </li>
<li>188 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
<li>46 </li>
<li>47 </li>
<li>48 </li>
<li>49 </li>
<li>50 </li>
<li>51 </li>
<li>52 </li>
<li>53 </li>
<li>54 </li>
<li>55 </li>
<li>56 </li>
<li>57 </li>
<li>58 </li>
<li>59 </li>
<li>60 </li>
<li>61 </li>
<li>62 </li>
<li>63 </li>
<li>64 </li>
<li>65 </li>
<li>66 </li>
<li>67 </li>
<li>68 </li>
<li>69 </li>
<li>70 </li>
<li>71 </li>
<li>72 </li>
<li>73 </li>
<li>74 </li>
<li>75 </li>
<li>76 </li>
<li>77 </li>
<li>78 </li>
<li>79 </li>
<li>80 </li>
<li>81 </li>
<li>82 </li>
<li>83 </li>
<li>84 </li>
<li>85 </li>
<li>86 </li>
<li>87 </li>
<li>88 </li>
<li>89 </li>
<li>90 </li>
<li>91 </li>
<li>92 </li>
<li>93 </li>
<li>94 </li>
<li>95 </li>
<li>96 </li>
<li>97 </li>
<li>98 </li>
<li>99 </li>
<li>100 </li>
<li>101 </li>
<li>102 </li>
<li>103 </li>
<li>104 </li>
<li>105 </li>
<li>106 </li>
<li>107 </li>
<li>108 </li>
<li>109 </li>
<li>110 </li>
<li>111 </li>
<li>112 </li>
<li>113 </li>
<li>114 </li>
<li>115 </li>
<li>116 </li>
<li>117 </li>
<li>118 </li>
<li>119 </li>
<li>120 </li>
<li>121 </li>
<li>122 </li>
<li>123 </li>
<li>124 </li>
<li>125 </li>
<li>126 </li>
<li>127 </li>
<li>128 </li>
<li>129 </li>
<li>130 </li>
<li>131 </li>
<li>132 </li>
<li>133 </li>
<li>134 </li>
<li>135 </li>
<li>136 </li>
<li>137 </li>
<li>138 </li>
<li>139 </li>
<li>140 </li>
<li>141 </li>
<li>142 </li>
<li>143 </li>
<li>144 </li>
<li>145 </li>
<li>146 </li>
<li>147 </li>
<li>148 </li>
<li>149 </li>
<li>150 </li>
<li>151 </li>
<li>152 </li>
<li>153 </li>
<li>154 </li>
<li>155 </li>
<li>156 </li>
<li>157 </li>
<li>158 </li>
<li>159 </li>
<li>160 </li>
<li>161 </li>
<li>162 </li>
<li>163 </li>
<li>164 </li>
<li>165 </li>
<li>166 </li>
<li>167 </li>
<li>168 </li>
<li>169 </li>
<li>170 </li>
<li>171 </li>
<li>172 </li>
<li>173 </li>
<li>174 </li>
<li>175 </li>
<li>176 </li>
<li>177 </li>
<li>178 </li>
<li>179 </li>
<li>180 </li>
<li>181 </li>
<li>182 </li>
<li>183 </li>
<li>184 </li>
<li>185 </li>
<li>186 </li>
<li>187 </li>
<li>188 </li>
</ul>
<pre><code>package org.springboot.sample.datasource;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 在方法上使用，用于指定使用哪个数据源
 *
 * @author   单红宇(365384722)
 * @myblog  http://blog.csdn.net/catoop/
 * @create    2016年1月23日
 */
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TargetDataSource {
    String name();
}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
</ul>
<p>本文代码博主是经过测试后没有问题才发出来共享给大家的。对于连接池参数配置会应用到所有数据源上。<br>比如配置一个：</p>
<pre><code>spring.datasource.maximum-pool-size=80
</code></pre><ul>
<li>1 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
</ul>
<p>那么我们所有的数据源都会自动应用上。</p>
<hr>
<p>补充：<br>如果你使用的是SpringMVC，并集成了Shiro，一般按网上的配置你可能是：</p>
<pre><code>&lt;bean class=&quot;org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator&quot; depends-on=&quot;lifecycleBeanPostProcessor&quot;&gt;
    &lt;property name=&quot;proxyTargetClass&quot; value=&quot;true&quot; /&gt;
&lt;/bean&gt;

&lt;bean class=&quot;org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor&quot;&gt;
    &lt;property name=&quot;securityManager&quot; ref=&quot;securityManager&quot;/&gt;
&lt;/bean&gt;
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
</ul>
<p>那么你请不要这样做，请按下面方法配置：</p>
<pre><code>    &lt;!-- AOP式方法级权限检查  --&gt;
    &lt;!-- 不要使用 DefaultAdvisorAutoProxyCreator 会出现二次代理的问题，这里不详述。 mark by shanhy 2016-05-15 --&gt;
    &lt;aop:config proxy-target-class=&quot;true&quot;/&gt;
    &lt;!-- 或者你使用了 &lt;aop:aspectj-autoproxy proxy-target-class=&quot;true&quot; /&gt; 也可以。 --&gt;

    &lt;bean class=&quot;org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor&quot;&gt;
        &lt;property name=&quot;securityManager&quot; ref=&quot;securityManager&quot;/&gt;
&lt;/bean&gt;
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
</ul>

        
        </div>
        <footer class="article-footer">
            <div class="share-container">


    <div class="bdsharebuttonbox">
    <a href="#" class="bds_more" data-cmd="more">分享到：</a>
    <a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间">QQ空间</a>
    <a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博">新浪微博</a>
    <a href="#" class="bds_tqq" data-cmd="tqq" title="分享到腾讯微博">腾讯微博</a>
    <a href="#" class="bds_renren" data-cmd="renren" title="分享到人人网">人人网</a>
    <a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信">微信</a>
</div>
<script>
window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{"bdSize":16}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];
</script>
<style>
    .bdshare_popup_box {
        border-radius: 4px;
        border: #e1e1e1 solid 1px;
    }
    .bdshare-button-style0-16 a,
    .bdshare-button-style0-16 .bds_more {
        padding-left: 20px;
        margin: 6px 10px 6px 0;
    }
    .bdshare_dialog_list a,
    .bdshare_popup_list a,
    .bdshare_popup_bottom a {
        font-family: 'Microsoft Yahei';
    }
    .bdshare_popup_top {
        display: none;
    }
    .bdshare_popup_bottom {
        height: auto;
        padding: 5px;
    }
</style>


</div>

            
    
        <a href="https://www.itchina.top/2018/04/20/Spring Boot 动态数据源（多数据源自动切换）/#comments" id="sourceId::2018/04/20/Spring Boot 动态数据源（多数据源自动切换）/" class="article-comment-link cy_cmt_count">评论</a>
    

        </footer>
    </div>
    
</article>



    <article id="post-Spring Boot Shiro 权限管理" class="article article-type-post" itemscope itemprop="blogPost">
    <div class="article-inner">
        
        
            <header class="article-header">
                
    
        <h1 itemprop="name">
            <a class="article-title" href="/2018/04/20/Spring Boot Shiro 权限管理/">Spring Boot Shiro 权限管理</a>
        </h1>
    

                
                    <div class="article-meta">
                        
    <div class="article-date">
        <i class="fa fa-calendar"></i>
        <a href="/2018/04/20/Spring Boot Shiro 权限管理/">
            <time datetime="2018-04-19T16:34:21.433Z" itemprop="datePublished">2018-04-20</time>
        </a>
    </div>


                        
    <div class="article-category">
    	<i class="fa fa-folder"></i>
        <a class="article-category-link" href="/categories/Spring/">Spring</a>
    </div>

                        
    <div class="article-tag">
        <i class="fa fa-tag"></i>
        <a class="tag-link" href="/tags/shiro/">shiro</a>, <a class="tag-link" href="/tags/spring/">spring</a>
    </div>

                    </div>
                
            </header>
        
        
        <div class="article-entry" itemprop="articleBody">
        
            
            <p>本来是打算接着写关于 <a href="http://lib.csdn.net/base/14" target="_blank" rel="noopener"> 数据库 </a><br>方面，集成MyBatis的，刚好赶上朋友问到Shiro权限管理，就先总结下发出来了。</p>
<p>使用Shiro之前用在Spring MVC中，是通过XML文件进行配置。<br>既然现在在写Spring Boot的帖子，就将Shiro应用到Spring<br>Boot中，我本地已经完成了SpringBoot使用Shiro的实例，将配置方法共享一下。</p>
<p>先简单介绍一下Shiro，对于没有用过Shiro的朋友，也算是做个简介吧。<br>Shiro是Apache下的一个开源项目，我们称之为Apache Shiro。它是一个很易用与 <a href="http://lib.csdn.net/base/17" target="_blank" rel="noopener"> Java
</a> 项目的的安全框架，提供了认证、授权、加密、会话管理，与 Spring Security<br>一样都是做一个权限的安全框架，但是与Spring Security 相比，在于 Shiro 使用了比较简单易懂易于使用的授权方式。</p>
<p>Apache Shiro 的三大核心组件<br><img src="https://img-blog.csdn.net/20160114233958301" alt="这里写图片描述"><br>- Subject 当前用户操作<br>- SecurityManager 用于管理所有的Subject<br>- Realms 用于进行权限信息的验证，也是我们需要自己实现的。</p>
<p>我们需要实现Realms的Authentication 和 Authorization。其中 Authentication<br>是用来验证用户身份，Authorization 是授权访问控制，用于对用户进行的操作授权，证明该用户是否允许进行当前操作，如访问某个链接，某个资源文件等。</p>
<p>Apache Shiro 核心通过 Filter 来实现，就好像SpringMvc 通过DispachServlet 来主控制一样。<br>既然是使用 Filter 一般也就能猜到，是通过URL规则来进行过滤和权限校验，所以我们需要定义一系列关于URL的规则和访问权限。</p>
<p>另外我们可以通过Shiro 提供的会话管理来获取Session中的信息。Shiro 也提供了缓存支持，使用 CacheManager 来管理。</p>
<p>官方网站： <a href="http://shiro.apache.org/" target="_blank" rel="noopener"> http://shiro.apache.org/ </a><br>完整 <a href="http://lib.csdn.net/base/16" target="_blank" rel="noopener"> 架构 </a> 图：<br><img src="https://img-blog.csdn.net/20160114234018824" alt="这里写图片描述"></p>
<p>下面我们通过代码实战来看下Spring Boot 中应用Shiro：<br>1、创建数据库表<br><img src="https://img-blog.csdn.net/20160114234036103" alt="这里写图片描述"></p>
<pre><code>表（t_permission）
    id  permissionname  role_id  
------  --------------  ---------
     1  add                     2
     2  del                     1
     3  update                  2
     4  query                   3
     5  user:query              1
     6  user:edit               2

表（t_role）
    id  rolename  
------  ----------
     1  admin     
     2  manager   
     3  normal    

表（t_user）
    id  username  password  
------  --------  ----------
     1  tom       123456    
     2  jack      123456    
     3  rose      123456  

表（t_user_role）
user_id  role_id  
-------  ---------
      1          1
      1          3
      2          2
      2          3
      3          3
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
</ul>
<p>看截图，上面3张表是我测试别的用的，可以忽略。</p>
<p>下面是，数据库脚本和测试数据。</p>
<pre><code>/*
SQLyog Ultimate v10.00 Beta1
MySQL - 5.5.28 : Database - test
*********************************************************************
*/


/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=&apos;&apos;*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE=&apos;NO_AUTO_VALUE_ON_ZERO&apos; */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`test` /*!40100 DEFAULT CHARACTER SET utf8 */;

USE `test`;

/*Table structure for table `t_permission` */

DROP TABLE IF EXISTS `t_permission`;

CREATE TABLE `t_permission` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `permissionname` varchar(32) DEFAULT NULL,
  `role_id` int(11) DEFAULT NULL,
  KEY `id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

/*Data for the table `t_permission` */

insert  into `t_permission`(`id`,`permissionname`,`role_id`) values (1,&apos;add&apos;,2),(2,&apos;del&apos;,1),(3,&apos;update&apos;,2),(4,&apos;query&apos;,3),(5,&apos;user:query&apos;,1),(6,&apos;user:edit&apos;,2);

/*Table structure for table `t_role` */

DROP TABLE IF EXISTS `t_role`;

CREATE TABLE `t_role` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `rolename` varchar(32) DEFAULT NULL,
  KEY `id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

/*Data for the table `t_role` */

insert  into `t_role`(`id`,`rolename`) values (1,&apos;admin&apos;),(2,&apos;manager&apos;),(3,&apos;normal&apos;);

/*Table structure for table `t_user` */

DROP TABLE IF EXISTS `t_user`;

CREATE TABLE `t_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(32) DEFAULT NULL,
  `password` varchar(32) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;

/*Data for the table `t_user` */

insert  into `t_user`(`id`,`username`,`password`) values (1,&apos;tom&apos;,&apos;123456&apos;),(2,&apos;jack&apos;,&apos;123456&apos;),(3,&apos;rose&apos;,&apos;123456&apos;);

/*Table structure for table `t_user_role` */

DROP TABLE IF EXISTS `t_user_role`;

CREATE TABLE `t_user_role` (
  `user_id` int(11) DEFAULT NULL,
  `role_id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

/*Data for the table `t_user_role` */

insert  into `t_user_role`(`user_id`,`role_id`) values (1,1),(1,3),(2,2),(2,3),(3,3);

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
<li>46 </li>
<li>47 </li>
<li>48 </li>
<li>49 </li>
<li>50 </li>
<li>51 </li>
<li>52 </li>
<li>53 </li>
<li>54 </li>
<li>55 </li>
<li>56 </li>
<li>57 </li>
<li>58 </li>
<li>59 </li>
<li>60 </li>
<li>61 </li>
<li>62 </li>
<li>63 </li>
<li>64 </li>
<li>65 </li>
<li>66 </li>
<li>67 </li>
<li>68 </li>
<li>69 </li>
<li>70 </li>
<li>71 </li>
<li>72 </li>
<li>73 </li>
<li>74 </li>
<li>75 </li>
<li>76 </li>
<li>77 </li>
<li>78 </li>
<li>79 </li>
<li>80 </li>
<li>81 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
<li>46 </li>
<li>47 </li>
<li>48 </li>
<li>49 </li>
<li>50 </li>
<li>51 </li>
<li>52 </li>
<li>53 </li>
<li>54 </li>
<li>55 </li>
<li>56 </li>
<li>57 </li>
<li>58 </li>
<li>59 </li>
<li>60 </li>
<li>61 </li>
<li>62 </li>
<li>63 </li>
<li>64 </li>
<li>65 </li>
<li>66 </li>
<li>67 </li>
<li>68 </li>
<li>69 </li>
<li>70 </li>
<li>71 </li>
<li>72 </li>
<li>73 </li>
<li>74 </li>
<li>75 </li>
<li>76 </li>
<li>77 </li>
<li>78 </li>
<li>79 </li>
<li>80 </li>
<li>81 </li>
</ul>
<p>2、创建对应实体类<br>User.java</p>
<pre><code>package org.springboot.sample.entity;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.hibernate.validator.constraints.NotEmpty;

/**
 * 用户
 *
 * @author 单红宇(365384722)
 * @myblog http://blog.csdn.net/catoop/
 * @create 2016年1月13日
 */
@Entity
@Table(name = &quot;t_user&quot;)
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    @NotEmpty(message = &quot;用户名不能为空&quot;)
    private String username;
    @NotEmpty(message = &quot;密码不能为空&quot;)
    private String password;    
    @ManyToMany(fetch=FetchType.EAGER)
    @JoinTable(name = &quot;t_user_role&quot;, joinColumns = { @JoinColumn(name = &quot;user_id&quot;) }, inverseJoinColumns = {
            @JoinColumn(name = &quot;role_id&quot;) })
    private List&lt;Role&gt; roleList;// 一个用户具有多个角色

    public User() {
        super();
    }

    public User(String username, String password) {
        super();
        this.username = username;
        this.password = password;
    }

    // 省略 get set 方法

    @Transient
    public Set&lt;String&gt; getRolesName() {
        List&lt;Role&gt; roles = getRoleList();
        Set&lt;String&gt; set = new HashSet&lt;String&gt;();
        for (Role role : roles) {
            set.add(role.getRolename());
        }
        return set;
    }

}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
<li>46 </li>
<li>47 </li>
<li>48 </li>
<li>49 </li>
<li>50 </li>
<li>51 </li>
<li>52 </li>
<li>53 </li>
<li>54 </li>
<li>55 </li>
<li>56 </li>
<li>57 </li>
<li>58 </li>
<li>59 </li>
<li>60 </li>
<li>61 </li>
<li>62 </li>
<li>63 </li>
<li>64 </li>
<li>65 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
<li>46 </li>
<li>47 </li>
<li>48 </li>
<li>49 </li>
<li>50 </li>
<li>51 </li>
<li>52 </li>
<li>53 </li>
<li>54 </li>
<li>55 </li>
<li>56 </li>
<li>57 </li>
<li>58 </li>
<li>59 </li>
<li>60 </li>
<li>61 </li>
<li>62 </li>
<li>63 </li>
<li>64 </li>
<li>65 </li>
</ul>
<p>Role.java</p>
<pre><code>package org.springboot.sample.entity;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;

/**
 * 角色（管理员，普通用户等）
 *
 * @author   单红宇(365384722)
 * @myblog  http://blog.csdn.net/catoop/
 * @create    2016年1月13日
 */
@Entity
@Table(name = &quot;t_role&quot;)
public class Role {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String rolename;
    @OneToMany(mappedBy = &quot;role&quot;, fetch=FetchType.EAGER)
    private List&lt;Permission&gt; permissionList;// 一个角色对应多个权限
    @ManyToMany
    @JoinTable(name = &quot;t_user_role&quot;, joinColumns = { @JoinColumn(name = &quot;role_id&quot;) }, inverseJoinColumns = {
            @JoinColumn(name = &quot;user_id&quot;) })
    private List&lt;User&gt; userList;// 一个角色对应多个用户

    // 省略 get set 方法

    @Transient
    public List&lt;String&gt; getPermissionsName() {
        List&lt;String&gt; list = new ArrayList&lt;String&gt;();
        List&lt;Permission&gt; perlist = getPermissionList();
        for (Permission per : perlist) {
            list.add(per.getPermissionname());
        }
        return list;
    }
}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
<li>46 </li>
<li>47 </li>
<li>48 </li>
<li>49 </li>
<li>50 </li>
<li>51 </li>
<li>52 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
<li>46 </li>
<li>47 </li>
<li>48 </li>
<li>49 </li>
<li>50 </li>
<li>51 </li>
<li>52 </li>
</ul>
<p>Permission.java</p>
<pre><code>package org.springboot.sample.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

/**
 * 权限（增删改查等）
 *
 * @author 单红宇(365384722)
 * @myblog http://blog.csdn.net/catoop/
 * @create 2016年1月13日
 */
@Entity
@Table(name = &quot;t_permission&quot;)
public class Permission {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String permissionname;

    @ManyToOne
    @JoinColumn(name = &quot;role_id&quot;)
    private Role role;// 一个权限对应一个角色

    // 省略 get set

}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
</ul>
<p>3、Shiro 配置，相当于SpringMVC 中的XML配置<br>ShiroConfiguration.java</p>
<pre><code>package org.springboot.sample.config;

import java.util.LinkedHashMap;
import java.util.Map;

import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springboot.sample.dao.IScoreDao;
import org.springboot.sample.security.MyShiroRealm;
import org.springboot.sample.service.StudentService;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;

/**
 * Shiro 配置
 *
 * @author   单红宇(365384722)
 * @myblog  http://blog.csdn.net/catoop/
 * @create    2016年1月13日
 */
@Configuration
public class ShiroConfiguration {

    private static final Logger logger = LoggerFactory.getLogger(ShiroConfiguration.class);

    @Bean
    public EhCacheManager getEhCacheManager() {  
        EhCacheManager em = new EhCacheManager();  
        em.setCacheManagerConfigFile(&quot;classpath:ehcache-shiro.xml&quot;);  
        return em;  
    }  

    @Bean(name = &quot;myShiroRealm&quot;)
    public MyShiroRealm myShiroRealm(EhCacheManager cacheManager) {  
        MyShiroRealm realm = new MyShiroRealm(); 
        realm.setCacheManager(cacheManager);
        return realm;
    }  

    /**
     * 注册DelegatingFilterProxy（Shiro）
     * 集成Shiro有2种方法：
     * 1. 按这个方法自己组装一个FilterRegistrationBean（这种方法更为灵活，可以自己定义UrlPattern，
     * 在项目使用中你可能会因为一些很但疼的问题最后采用它， 想使用它你可能需要看官网或者已经很了解Shiro的处理原理了）
     * 2. 直接使用ShiroFilterFactoryBean（这种方法比较简单，其内部对ShiroFilter做了组装工作，无法自己定义UrlPattern，
     * 默认拦截 /*）
     *
     * @param dispatcherServlet
     * @return
     * @author SHANHY
     * @create  2016年1月13日
     */
//  @Bean
//  public FilterRegistrationBean filterRegistrationBean() {
//      FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
//      filterRegistration.setFilter(new DelegatingFilterProxy(&quot;shiroFilter&quot;));
//      //  该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理  
//      filterRegistration.addInitParameter(&quot;targetFilterLifecycle&quot;, &quot;true&quot;);
//      filterRegistration.setEnabled(true);
//      filterRegistration.addUrlPatterns(&quot;/*&quot;);// 可以自己灵活的定义很多，避免一些根本不需要被Shiro处理的请求被包含进来
//      return filterRegistration;
//  }

    @Bean(name = &quot;lifecycleBeanPostProcessor&quot;)
    public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
        daap.setProxyTargetClass(true);
        return daap;
    }

    @Bean(name = &quot;securityManager&quot;)
    public DefaultWebSecurityManager getDefaultWebSecurityManager(MyShiroRealm myShiroRealm) {
        DefaultWebSecurityManager dwsm = new DefaultWebSecurityManager();
        dwsm.setRealm(myShiroRealm);
//      &lt;!-- 用户授权/认证信息Cache, 采用EhCache 缓存 --&gt; 
        dwsm.setCacheManager(getEhCacheManager());
        return dwsm;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();
        aasa.setSecurityManager(securityManager);
        return aasa;
    }

    /**
     * 加载shiroFilter权限控制规则（从数据库读取然后配置）
     *
     * @author SHANHY
     * @create  2016年1月14日
     */
    private void loadShiroFilterChain(ShiroFilterFactoryBean shiroFilterFactoryBean, StudentService stuService, IScoreDao scoreDao){
        /////////////////////// 下面这些规则配置最好配置到配置文件中 ///////////////////////
        Map&lt;String, String&gt; filterChainDefinitionMap = new LinkedHashMap&lt;String, String&gt;();
        // authc：该过滤器下的页面必须验证后才能访问，它是Shiro内置的一个拦截器org.apache.shiro.web.filter.authc.FormAuthenticationFilter
        filterChainDefinitionMap.put(&quot;/user&quot;, &quot;authc&quot;);// 这里为了测试，只限制/user，实际开发中请修改为具体拦截的请求规则
        // anon：它对应的过滤器里面是空的,什么都没做
        logger.info(&quot;##################从数据库读取权限规则，加载到shiroFilter中##################&quot;);
        filterChainDefinitionMap.put(&quot;/user/edit/**&quot;, &quot;authc,perms[user:edit]&quot;);// 这里为了测试，固定写死的值，也可以从数据库或其他配置中读取

        filterChainDefinitionMap.put(&quot;/login&quot;, &quot;anon&quot;);
        filterChainDefinitionMap.put(&quot;/**&quot;, &quot;anon&quot;);//anon 可以理解为不拦截

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
    }

    /**
     * ShiroFilter&lt;br/&gt;
     * 注意这里参数中的 StudentService 和 IScoreDao 只是一个例子，因为我们在这里可以用这样的方式获取到相关访问数据库的对象，
     * 然后读取数据库相关配置，配置到 shiroFilterFactoryBean 的访问规则中。实际项目中，请使用自己的Service来处理业务逻辑。
     *
     * @param myShiroRealm
     * @param stuService
     * @param scoreDao
     * @return
     * @author SHANHY
     * @create  2016年1月14日
     */
    @Bean(name = &quot;shiroFilter&quot;)
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager securityManager, StudentService stuService, IScoreDao scoreDao) {

        ShiroFilterFactoryBean shiroFilterFactoryBean = new MShiroFilterFactoryBean();
        // 必须设置 SecurityManager  
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 如果不设置默认会自动寻找Web工程根目录下的&quot;/login.jsp&quot;页面
        shiroFilterFactoryBean.setLoginUrl(&quot;/login&quot;);
        // 登录成功后要跳转的连接
        shiroFilterFactoryBean.setSuccessUrl(&quot;/user&quot;);
        shiroFilterFactoryBean.setUnauthorizedUrl(&quot;/403&quot;);

        loadShiroFilterChain(shiroFilterFactoryBean, stuService, scoreDao);
        return shiroFilterFactoryBean;
    }

}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
<li>46 </li>
<li>47 </li>
<li>48 </li>
<li>49 </li>
<li>50 </li>
<li>51 </li>
<li>52 </li>
<li>53 </li>
<li>54 </li>
<li>55 </li>
<li>56 </li>
<li>57 </li>
<li>58 </li>
<li>59 </li>
<li>60 </li>
<li>61 </li>
<li>62 </li>
<li>63 </li>
<li>64 </li>
<li>65 </li>
<li>66 </li>
<li>67 </li>
<li>68 </li>
<li>69 </li>
<li>70 </li>
<li>71 </li>
<li>72 </li>
<li>73 </li>
<li>74 </li>
<li>75 </li>
<li>76 </li>
<li>77 </li>
<li>78 </li>
<li>79 </li>
<li>80 </li>
<li>81 </li>
<li>82 </li>
<li>83 </li>
<li>84 </li>
<li>85 </li>
<li>86 </li>
<li>87 </li>
<li>88 </li>
<li>89 </li>
<li>90 </li>
<li>91 </li>
<li>92 </li>
<li>93 </li>
<li>94 </li>
<li>95 </li>
<li>96 </li>
<li>97 </li>
<li>98 </li>
<li>99 </li>
<li>100 </li>
<li>101 </li>
<li>102 </li>
<li>103 </li>
<li>104 </li>
<li>105 </li>
<li>106 </li>
<li>107 </li>
<li>108 </li>
<li>109 </li>
<li>110 </li>
<li>111 </li>
<li>112 </li>
<li>113 </li>
<li>114 </li>
<li>115 </li>
<li>116 </li>
<li>117 </li>
<li>118 </li>
<li>119 </li>
<li>120 </li>
<li>121 </li>
<li>122 </li>
<li>123 </li>
<li>124 </li>
<li>125 </li>
<li>126 </li>
<li>127 </li>
<li>128 </li>
<li>129 </li>
<li>130 </li>
<li>131 </li>
<li>132 </li>
<li>133 </li>
<li>134 </li>
<li>135 </li>
<li>136 </li>
<li>137 </li>
<li>138 </li>
<li>139 </li>
<li>140 </li>
<li>141 </li>
<li>142 </li>
<li>143 </li>
<li>144 </li>
<li>145 </li>
<li>146 </li>
<li>147 </li>
<li>148 </li>
<li>149 </li>
<li>150 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
<li>46 </li>
<li>47 </li>
<li>48 </li>
<li>49 </li>
<li>50 </li>
<li>51 </li>
<li>52 </li>
<li>53 </li>
<li>54 </li>
<li>55 </li>
<li>56 </li>
<li>57 </li>
<li>58 </li>
<li>59 </li>
<li>60 </li>
<li>61 </li>
<li>62 </li>
<li>63 </li>
<li>64 </li>
<li>65 </li>
<li>66 </li>
<li>67 </li>
<li>68 </li>
<li>69 </li>
<li>70 </li>
<li>71 </li>
<li>72 </li>
<li>73 </li>
<li>74 </li>
<li>75 </li>
<li>76 </li>
<li>77 </li>
<li>78 </li>
<li>79 </li>
<li>80 </li>
<li>81 </li>
<li>82 </li>
<li>83 </li>
<li>84 </li>
<li>85 </li>
<li>86 </li>
<li>87 </li>
<li>88 </li>
<li>89 </li>
<li>90 </li>
<li>91 </li>
<li>92 </li>
<li>93 </li>
<li>94 </li>
<li>95 </li>
<li>96 </li>
<li>97 </li>
<li>98 </li>
<li>99 </li>
<li>100 </li>
<li>101 </li>
<li>102 </li>
<li>103 </li>
<li>104 </li>
<li>105 </li>
<li>106 </li>
<li>107 </li>
<li>108 </li>
<li>109 </li>
<li>110 </li>
<li>111 </li>
<li>112 </li>
<li>113 </li>
<li>114 </li>
<li>115 </li>
<li>116 </li>
<li>117 </li>
<li>118 </li>
<li>119 </li>
<li>120 </li>
<li>121 </li>
<li>122 </li>
<li>123 </li>
<li>124 </li>
<li>125 </li>
<li>126 </li>
<li>127 </li>
<li>128 </li>
<li>129 </li>
<li>130 </li>
<li>131 </li>
<li>132 </li>
<li>133 </li>
<li>134 </li>
<li>135 </li>
<li>136 </li>
<li>137 </li>
<li>138 </li>
<li>139 </li>
<li>140 </li>
<li>141 </li>
<li>142 </li>
<li>143 </li>
<li>144 </li>
<li>145 </li>
<li>146 </li>
<li>147 </li>
<li>148 </li>
<li>149 </li>
<li>150 </li>
</ul>
<pre><code>/**
 * 继承 ShiroFilterFactoryBean 处理拦截资源文件问题。
 *
 * @author   单红宇(365384722)
 * @myblog  http://blog.csdn.net/catoop/
 * @create    2016年3月8日
 */
public class MShiroFilterFactoryBean extends ShiroFilterFactoryBean {

    // 对ShiroFilter来说，需要直接忽略的请求
    private Set&lt;String&gt; ignoreExt;

    public MShiroFilterFactoryBean() {
        super();
        ignoreExt = new HashSet&lt;&gt;();
        ignoreExt.add(&quot;.jpg&quot;);
        ignoreExt.add(&quot;.png&quot;);
        ignoreExt.add(&quot;.gif&quot;);
        ignoreExt.add(&quot;.bmp&quot;);
        ignoreExt.add(&quot;.js&quot;);
        ignoreExt.add(&quot;.css&quot;);
    }

    @Override
    protected AbstractShiroFilter createInstance() throws Exception {

        SecurityManager securityManager = getSecurityManager();
        if (securityManager == null) {
            String msg = &quot;SecurityManager property must be set.&quot;;
            throw new BeanInitializationException(msg);
        }

        if (!(securityManager instanceof WebSecurityManager)) {
            String msg = &quot;The security manager does not implement the WebSecurityManager interface.&quot;;
            throw new BeanInitializationException(msg);
        }

        FilterChainManager manager = createFilterChainManager();

        PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
        chainResolver.setFilterChainManager(manager);

        return new MSpringShiroFilter((WebSecurityManager) securityManager, chainResolver);
    }

    private final class MSpringShiroFilter extends AbstractShiroFilter {

        protected MSpringShiroFilter(WebSecurityManager webSecurityManager, FilterChainResolver resolver) {
            super();
            if (webSecurityManager == null) {
                throw new IllegalArgumentException(&quot;WebSecurityManager property cannot be null.&quot;);
            }
            setSecurityManager(webSecurityManager);
            if (resolver != null) {
                setFilterChainResolver(resolver);
            }
        }

        @Override
        protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse,
                FilterChain chain) throws ServletException, IOException {
            HttpServletRequest request = (HttpServletRequest)servletRequest;
            String str = request.getRequestURI().toLowerCase();
            // 因为ShiroFilter 拦截所有请求（在上面我们配置了urlPattern 为 * ，当然你也可以在那里精确的添加要处理的路径，这样就不需要这个类了），而在每次请求里面都做了session的读取和更新访问时间等操作，这样在集群部署session共享的情况下，数量级的加大了处理量负载。
            // 所以我们这里将一些能忽略的请求忽略掉。
            // 当然如果你的集群系统使用了动静分离处理，静态资料的请求不会到Filter这个层面，便可以忽略。
            boolean flag = true;
            int idx = 0;
            if(( idx = str.indexOf(&quot;.&quot;)) &gt; 0){
                str = str.substring(idx);
                if(ignoreExt.contains(str.toLowerCase()))
                    flag = false;
            }
            if(flag){
                super.doFilterInternal(servletRequest, servletResponse, chain);
            }else{
                chain.doFilter(servletRequest, servletResponse);
            }
        }

    }
}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
<li>46 </li>
<li>47 </li>
<li>48 </li>
<li>49 </li>
<li>50 </li>
<li>51 </li>
<li>52 </li>
<li>53 </li>
<li>54 </li>
<li>55 </li>
<li>56 </li>
<li>57 </li>
<li>58 </li>
<li>59 </li>
<li>60 </li>
<li>61 </li>
<li>62 </li>
<li>63 </li>
<li>64 </li>
<li>65 </li>
<li>66 </li>
<li>67 </li>
<li>68 </li>
<li>69 </li>
<li>70 </li>
<li>71 </li>
<li>72 </li>
<li>73 </li>
<li>74 </li>
<li>75 </li>
<li>76 </li>
<li>77 </li>
<li>78 </li>
<li>79 </li>
<li>80 </li>
<li>81 </li>
<li>82 </li>
<li>83 </li>
<li>84 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
<li>46 </li>
<li>47 </li>
<li>48 </li>
<li>49 </li>
<li>50 </li>
<li>51 </li>
<li>52 </li>
<li>53 </li>
<li>54 </li>
<li>55 </li>
<li>56 </li>
<li>57 </li>
<li>58 </li>
<li>59 </li>
<li>60 </li>
<li>61 </li>
<li>62 </li>
<li>63 </li>
<li>64 </li>
<li>65 </li>
<li>66 </li>
<li>67 </li>
<li>68 </li>
<li>69 </li>
<li>70 </li>
<li>71 </li>
<li>72 </li>
<li>73 </li>
<li>74 </li>
<li>75 </li>
<li>76 </li>
<li>77 </li>
<li>78 </li>
<li>79 </li>
<li>80 </li>
<li>81 </li>
<li>82 </li>
<li>83 </li>
<li>84 </li>
</ul>
<p>其中的 ehcache-shiro.xml 在 src/main/resources 下面，内容为：</p>
<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;ehcache updateCheck=&quot;false&quot; name=&quot;shiroCache&quot;&gt;

    &lt;defaultCache
            maxElementsInMemory=&quot;10000&quot;
            eternal=&quot;false&quot;
            timeToIdleSeconds=&quot;120&quot;
            timeToLiveSeconds=&quot;120&quot;
            overflowToDisk=&quot;false&quot;
            diskPersistent=&quot;false&quot;
            diskExpiryThreadIntervalSeconds=&quot;120&quot;
            /&gt;
&lt;/ehcache&gt;
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
</ul>
<p>4、继承 AuthorizingRealm 实现认证和授权2个方法<br>MyShiroRealm.java</p>
<pre><code>package org.springboot.sample.security;

import java.util.List;

import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springboot.sample.dao.IUserDao;
import org.springboot.sample.entity.Role;
import org.springboot.sample.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * MyShiroRealm
 *
 * @author   单红宇(365384722)
 * @myblog  http://blog.csdn.net/catoop/
 * @create    2016年1月13日
 */
public class MyShiroRealm extends AuthorizingRealm{

    private static final Logger logger = LoggerFactory.getLogger(MyShiroRealm.class);

    @Autowired
    private IUserDao userDao; 

    /**
     * 权限认证，为当前登录的Subject授予角色和权限 
     * @see 经测试：本例中该方法的调用时机为需授权资源被访问时 
     * @see 经测试：并且每次访问需授权资源时都会执行该方法中的逻辑，这表明本例中默认并未启用AuthorizationCache 
     * @see 经测试：如果连续访问同一个URL（比如刷新），该方法不会被重复调用，Shiro有一个时间间隔（也就是cache时间，在ehcache-shiro.xml中配置），超过这个时间间隔再刷新页面，该方法会被执行
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        logger.info(&quot;##################执行Shiro权限认证##################&quot;);
        //获取当前登录输入的用户名，等价于(String) principalCollection.fromRealm(getName()).iterator().next();
        String loginName = (String)super.getAvailablePrincipal(principalCollection); 
        //到数据库查是否有此对象
        User user=userDao.findByName(loginName);// 实际项目中，这里可以根据实际情况做缓存，如果不做，Shiro自己也是有时间间隔机制，2分钟内不会重复执行该方法
        if(user!=null){
            //权限信息对象info,用来存放查出的用户的所有的角色（role）及权限（permission）
            SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
            //用户的角色集合
            info.setRoles(user.getRolesName());
            //用户的角色对应的所有权限，如果只使用角色定义访问权限，下面的四行可以不要
            List&lt;Role&gt; roleList=user.getRoleList();
            for (Role role : roleList) {
                info.addStringPermissions(role.getPermissionsName());
            }
            // 或者按下面这样添加
            //添加一个角色,不是配置意义上的添加,而是证明该用户拥有admin角色    
//            simpleAuthorInfo.addRole(&quot;admin&quot;);  
            //添加权限  
//            simpleAuthorInfo.addStringPermission(&quot;admin:manage&quot;);  
//            logger.info(&quot;已为用户[mike]赋予了[admin]角色和[admin:manage]权限&quot;);
            return info;
        }
        // 返回null的话，就会导致任何用户访问被拦截的请求时，都会自动跳转到unauthorizedUrl指定的地址
        return null;
    }

    /**
     * 登录认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken authenticationToken) throws AuthenticationException {
        //UsernamePasswordToken对象用来存放提交的登录信息
        UsernamePasswordToken token=(UsernamePasswordToken) authenticationToken;

        logger.info(&quot;验证当前Subject时获取到token为：&quot; + ReflectionToStringBuilder.toString(token, ToStringStyle.MULTI_LINE_STYLE)); 

        //查出是否有此用户
        User user=userDao.findByName(token.getUsername());
        if(user!=null){
            // 若存在，将此用户存放到登录认证info中，无需自己做密码对比，Shiro会为我们进行密码对比校验
            return new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName());
        }
        return null;
    }
}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
<li>46 </li>
<li>47 </li>
<li>48 </li>
<li>49 </li>
<li>50 </li>
<li>51 </li>
<li>52 </li>
<li>53 </li>
<li>54 </li>
<li>55 </li>
<li>56 </li>
<li>57 </li>
<li>58 </li>
<li>59 </li>
<li>60 </li>
<li>61 </li>
<li>62 </li>
<li>63 </li>
<li>64 </li>
<li>65 </li>
<li>66 </li>
<li>67 </li>
<li>68 </li>
<li>69 </li>
<li>70 </li>
<li>71 </li>
<li>72 </li>
<li>73 </li>
<li>74 </li>
<li>75 </li>
<li>76 </li>
<li>77 </li>
<li>78 </li>
<li>79 </li>
<li>80 </li>
<li>81 </li>
<li>82 </li>
<li>83 </li>
<li>84 </li>
<li>85 </li>
<li>86 </li>
<li>87 </li>
<li>88 </li>
<li>89 </li>
<li>90 </li>
<li>91 </li>
<li>92 </li>
<li>93 </li>
<li>94 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
<li>46 </li>
<li>47 </li>
<li>48 </li>
<li>49 </li>
<li>50 </li>
<li>51 </li>
<li>52 </li>
<li>53 </li>
<li>54 </li>
<li>55 </li>
<li>56 </li>
<li>57 </li>
<li>58 </li>
<li>59 </li>
<li>60 </li>
<li>61 </li>
<li>62 </li>
<li>63 </li>
<li>64 </li>
<li>65 </li>
<li>66 </li>
<li>67 </li>
<li>68 </li>
<li>69 </li>
<li>70 </li>
<li>71 </li>
<li>72 </li>
<li>73 </li>
<li>74 </li>
<li>75 </li>
<li>76 </li>
<li>77 </li>
<li>78 </li>
<li>79 </li>
<li>80 </li>
<li>81 </li>
<li>82 </li>
<li>83 </li>
<li>84 </li>
<li>85 </li>
<li>86 </li>
<li>87 </li>
<li>88 </li>
<li>89 </li>
<li>90 </li>
<li>91 </li>
<li>92 </li>
<li>93 </li>
<li>94 </li>
</ul>
<p>注意：其中 userDao.findByName 这个代码就不贴上了，也没啥可贴的，根据姓名查询一个对象而已。</p>
<p>5、编写测试的 Controller 和测试 jsp 页面<br>ShiroController.java</p>
<pre><code>package org.springboot.sample.controller;

import java.util.Map;

import javax.validation.Valid;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springboot.sample.dao.IUserDao;
import org.springboot.sample.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

/**
 * Shiro测试Controller
 *
 * @author   单红宇(365384722)
 * @myblog  http://blog.csdn.net/catoop/
 * @create    2016年1月13日
 */
@Controller
public class ShiroController {

    private static final Logger logger = LoggerFactory.getLogger(ShiroController.class);

    @Autowired
    private IUserDao userDao;

    @RequestMapping(value=&quot;/login&quot;,method=RequestMethod.GET)
    public String loginForm(Model model){
        model.addAttribute(&quot;user&quot;, new User());
        return &quot;login&quot;;
    }

    @RequestMapping(value=&quot;/login&quot;,method=RequestMethod.POST)
    public String login(@Valid User user,BindingResult bindingResult,RedirectAttributes redirectAttributes){
        if(bindingResult.hasErrors()){
            return &quot;login&quot;;
        }

        String username = user.getUsername();
        UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());
        //获取当前的Subject  
        Subject currentUser = SecurityUtils.getSubject();  
        try {  
            //在调用了login方法后,SecurityManager会收到AuthenticationToken,并将其发送给已配置的Realm执行必须的认证检查  
            //每个Realm都能在必要时对提交的AuthenticationTokens作出反应  
            //所以这一步在调用login(token)方法时,它会走到MyRealm.doGetAuthenticationInfo()方法中,具体验证方式详见此方法  
            logger.info(&quot;对用户[&quot; + username + &quot;]进行登录验证..验证开始&quot;);  
            currentUser.login(token);  
            logger.info(&quot;对用户[&quot; + username + &quot;]进行登录验证..验证通过&quot;);  
        }catch(UnknownAccountException uae){  
            logger.info(&quot;对用户[&quot; + username + &quot;]进行登录验证..验证未通过,未知账户&quot;);  
            redirectAttributes.addFlashAttribute(&quot;message&quot;, &quot;未知账户&quot;);  
        }catch(IncorrectCredentialsException ice){  
            logger.info(&quot;对用户[&quot; + username + &quot;]进行登录验证..验证未通过,错误的凭证&quot;);  
            redirectAttributes.addFlashAttribute(&quot;message&quot;, &quot;密码不正确&quot;);  
        }catch(LockedAccountException lae){  
            logger.info(&quot;对用户[&quot; + username + &quot;]进行登录验证..验证未通过,账户已锁定&quot;);  
            redirectAttributes.addFlashAttribute(&quot;message&quot;, &quot;账户已锁定&quot;);  
        }catch(ExcessiveAttemptsException eae){  
            logger.info(&quot;对用户[&quot; + username + &quot;]进行登录验证..验证未通过,错误次数过多&quot;);  
            redirectAttributes.addFlashAttribute(&quot;message&quot;, &quot;用户名或密码错误次数过多&quot;);  
        }catch(AuthenticationException ae){  
            //通过处理Shiro的运行时AuthenticationException就可以控制用户登录失败或密码错误时的情景  
            logger.info(&quot;对用户[&quot; + username + &quot;]进行登录验证..验证未通过,堆栈轨迹如下&quot;);  
            ae.printStackTrace();  
            redirectAttributes.addFlashAttribute(&quot;message&quot;, &quot;用户名或密码不正确&quot;);  
        }  
        //验证是否登录成功  
        if(currentUser.isAuthenticated()){  
            logger.info(&quot;用户[&quot; + username + &quot;]登录认证通过(这里可以进行一些认证通过后的一些系统参数初始化操作)&quot;);  
            return &quot;redirect:/user&quot;;
        }else{  
            token.clear();  
            return &quot;redirect:/login&quot;;
        }  
    }

    @RequestMapping(value=&quot;/logout&quot;,method=RequestMethod.GET)  
    public String logout(RedirectAttributes redirectAttributes ){ 
        //使用权限管理工具进行用户的退出，跳出登录，给出提示信息
        SecurityUtils.getSubject().logout();  
        redirectAttributes.addFlashAttribute(&quot;message&quot;, &quot;您已安全退出&quot;);  
        return &quot;redirect:/login&quot;;
    } 

    @RequestMapping(&quot;/403&quot;)
    public String unauthorizedRole(){
        logger.info(&quot;------没有权限-------&quot;);
        return &quot;403&quot;;
    }

    @RequestMapping(&quot;/user&quot;)
    public String getUserList(Map&lt;String, Object&gt; model){
        model.put(&quot;userList&quot;, userDao.getList());
        return &quot;user&quot;;
    }

    @RequestMapping(&quot;/user/edit/{userid}&quot;)
    public String getUserList(@PathVariable int userid){
        logger.info(&quot;------进入用户信息修改-------&quot;);
        return &quot;user_edit&quot;;
    }
}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
<li>46 </li>
<li>47 </li>
<li>48 </li>
<li>49 </li>
<li>50 </li>
<li>51 </li>
<li>52 </li>
<li>53 </li>
<li>54 </li>
<li>55 </li>
<li>56 </li>
<li>57 </li>
<li>58 </li>
<li>59 </li>
<li>60 </li>
<li>61 </li>
<li>62 </li>
<li>63 </li>
<li>64 </li>
<li>65 </li>
<li>66 </li>
<li>67 </li>
<li>68 </li>
<li>69 </li>
<li>70 </li>
<li>71 </li>
<li>72 </li>
<li>73 </li>
<li>74 </li>
<li>75 </li>
<li>76 </li>
<li>77 </li>
<li>78 </li>
<li>79 </li>
<li>80 </li>
<li>81 </li>
<li>82 </li>
<li>83 </li>
<li>84 </li>
<li>85 </li>
<li>86 </li>
<li>87 </li>
<li>88 </li>
<li>89 </li>
<li>90 </li>
<li>91 </li>
<li>92 </li>
<li>93 </li>
<li>94 </li>
<li>95 </li>
<li>96 </li>
<li>97 </li>
<li>98 </li>
<li>99 </li>
<li>100 </li>
<li>101 </li>
<li>102 </li>
<li>103 </li>
<li>104 </li>
<li>105 </li>
<li>106 </li>
<li>107 </li>
<li>108 </li>
<li>109 </li>
<li>110 </li>
<li>111 </li>
<li>112 </li>
<li>113 </li>
<li>114 </li>
<li>115 </li>
<li>116 </li>
<li>117 </li>
<li>118 </li>
<li>119 </li>
<li>120 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
<li>46 </li>
<li>47 </li>
<li>48 </li>
<li>49 </li>
<li>50 </li>
<li>51 </li>
<li>52 </li>
<li>53 </li>
<li>54 </li>
<li>55 </li>
<li>56 </li>
<li>57 </li>
<li>58 </li>
<li>59 </li>
<li>60 </li>
<li>61 </li>
<li>62 </li>
<li>63 </li>
<li>64 </li>
<li>65 </li>
<li>66 </li>
<li>67 </li>
<li>68 </li>
<li>69 </li>
<li>70 </li>
<li>71 </li>
<li>72 </li>
<li>73 </li>
<li>74 </li>
<li>75 </li>
<li>76 </li>
<li>77 </li>
<li>78 </li>
<li>79 </li>
<li>80 </li>
<li>81 </li>
<li>82 </li>
<li>83 </li>
<li>84 </li>
<li>85 </li>
<li>86 </li>
<li>87 </li>
<li>88 </li>
<li>89 </li>
<li>90 </li>
<li>91 </li>
<li>92 </li>
<li>93 </li>
<li>94 </li>
<li>95 </li>
<li>96 </li>
<li>97 </li>
<li>98 </li>
<li>99 </li>
<li>100 </li>
<li>101 </li>
<li>102 </li>
<li>103 </li>
<li>104 </li>
<li>105 </li>
<li>106 </li>
<li>107 </li>
<li>108 </li>
<li>109 </li>
<li>110 </li>
<li>111 </li>
<li>112 </li>
<li>113 </li>
<li>114 </li>
<li>115 </li>
<li>116 </li>
<li>117 </li>
<li>118 </li>
<li>119 </li>
<li>120 </li>
</ul>
<p>login.jsp</p>
<pre><code>&lt;%@ page language=&quot;java&quot; import=&quot;java.util.*&quot; pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;%@ taglib prefix=&quot;form&quot; uri=&quot;http://www.springframework.org/tags/form&quot;%&gt;
&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Login&lt;/title&gt;
&lt;/head&gt;

&lt;body&gt;
    &lt;h1&gt;登录页面----${message }&lt;/h1&gt;
    &lt;img alt=&quot;&quot; src=&quot;${pageContext.request.contextPath }/pic.jpg&quot;&gt;
    &lt;form:form action=&quot;${pageContext.request.contextPath }/login&quot;
        commandName=&quot;user&quot; method=&quot;post&quot;&gt;
        用户名：&lt;form:input path=&quot;username&quot; /&gt;
        &lt;form:errors path=&quot;username&quot; cssClass=&quot;error&quot; /&gt;
        &lt;br /&gt;
        密码：&lt;form:password path=&quot;password&quot; /&gt;
        &lt;form:errors path=&quot;password&quot; cssClass=&quot;error&quot; /&gt;
        &lt;br /&gt;
        &lt;form:button name=&quot;button&quot;&gt;提交&lt;/form:button&gt;
    &lt;/form:form&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
</ul>
<p>user.jsp</p>
<pre><code>&lt;%@ page language=&quot;java&quot; import=&quot;java.util.*&quot; pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;%@ taglib prefix=&quot;c&quot; uri=&quot;http://java.sun.com/jsp/jstl/core&quot; %&gt;
&lt;%@ taglib prefix=&quot;shiro&quot; uri=&quot;http://shiro.apache.org/tags&quot; %&gt;
&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;&gt;
&lt;html&gt;
  &lt;head&gt;
    &lt;title&gt;用户列表&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;h1&gt;${message }&lt;/h1&gt;
    &lt;h1&gt;用户列表--&lt;a href=&quot;${pageContext.request.contextPath }/logout&quot;&gt;退出登录&lt;/a&gt;    &lt;/h1&gt;
    &lt;h2&gt;权限列表&lt;/h2&gt;
    &lt;shiro:authenticated&gt;用户已经登录显示此内容&lt;br/&gt;&lt;/shiro:authenticated&gt;&lt;br/&gt;
    &lt;shiro:hasRole name=&quot;manager&quot;&gt;manager角色登录显示此内容&lt;br/&gt;&lt;/shiro:hasRole&gt;
    &lt;shiro:hasRole name=&quot;admin&quot;&gt;admin角色登录显示此内容&lt;br/&gt;&lt;/shiro:hasRole&gt;
    &lt;shiro:hasRole name=&quot;normal&quot;&gt;normal角色登录显示此内容&lt;br/&gt;&lt;/shiro:hasRole&gt;&lt;br/&gt;

    &lt;shiro:hasAnyRoles name=&quot;manager,admin&quot;&gt;manager or admin 角色用户登录显示此内容&lt;br/&gt;&lt;/shiro:hasAnyRoles&gt;&lt;br/&gt;
    &lt;shiro:principal/&gt;-显示当前登录用户名&lt;br/&gt;&lt;br/&gt;
    &lt;shiro:hasPermission name=&quot;add&quot;&gt;add权限用户显示此内容&lt;br/&gt;&lt;/shiro:hasPermission&gt;
    &lt;shiro:hasPermission name=&quot;user:query&quot;&gt;user:query权限用户显示此内容&lt;br/&gt;&lt;/shiro:hasPermission&gt;
    &lt;shiro:lacksPermission name=&quot;user:query&quot;&gt;不具有user:query权限的用户显示此内容 &lt;br/&gt;&lt;/shiro:lacksPermission&gt;

    &lt;br/&gt;所有用户列表：&lt;br/&gt;
    &lt;ul&gt;
        &lt;c:forEach items=&quot;${userList }&quot; var=&quot;user&quot;&gt;
            &lt;li&gt;用户名：${user.username }----密码：${user.password }----&lt;a href=&quot;${pageContext.request.contextPath }/user/edit/${user.id}&quot;&gt;修改用户（测试根据不同用户可访问权限不同，本例tom无权限，jack有权限）&lt;/a&gt;&lt;/li&gt;
        &lt;/c:forEach&gt;
    &lt;/ul&gt;
    &lt;img alt=&quot;&quot; src=&quot;${pageContext.request.contextPath }/pic.jpg&quot;&gt;
    &lt;script type=&quot;text/javascript&quot; src=&quot;${pageContext.request.contextPath }/webjarslocator/jquery/jquery.js&quot;&gt;&lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
</ul>
<p>user_edit.jsp</p>
<pre><code>&lt;%@ page language=&quot;java&quot; import=&quot;java.util.*&quot; pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;%@ taglib prefix=&quot;c&quot; uri=&quot;http://java.sun.com/jsp/jstl/core&quot; %&gt;
&lt;%@ taglib prefix=&quot;shiro&quot; uri=&quot;http://shiro.apache.org/tags&quot; %&gt;
&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;&gt;
&lt;html&gt;
  &lt;head&gt;
    &lt;title&gt;用户信息 - 修改&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;h2&gt;修改用户信息页面&lt;/h2&gt;&lt;br/&gt;
    &lt;a href=&quot;${pageContext.request.contextPath }/user&quot;&gt;返回用户列表&lt;/a&gt;
  &lt;/body&gt;
&lt;/html&gt;
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
</ul>
<p>403.jsp</p>
<pre><code>&lt;%@ page language=&quot;java&quot; import=&quot;java.util.*&quot; pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;%@ taglib prefix=&quot;form&quot; uri=&quot;http://www.springframework.org/tags/form&quot; %&gt;
&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;&gt;
&lt;html&gt;
  &lt;head&gt;
    &lt;title&gt;权限错误&lt;/title&gt;
  &lt;/head&gt;

  &lt;body&gt;
    &lt;h1&gt;对不起，您没有权限请求此连接！&lt;/h1&gt;
    &lt;img alt=&quot;&quot; src=&quot;${pageContext.request.contextPath }/pic.jpg&quot;&gt;

  &lt;/body&gt;
&lt;/html&gt;
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
</ul>
<p>其中的pic.jpg 是测试代码遗留的，没有任何用处。关于 Controller 和 JSP 页面本文不做介绍，关于Spring Boot<br>使用Controller 和 JSP ，前面已经有文章介绍。</p>
<p>启动服务后访问 <a href="http://localhost:8080/myspringboot/user" target="_blank" rel="noopener"> http://localhost:8080/myspringboot/user
</a> 会自动跳到 login 页面。<br>登录成功后，会打开 user 页面（关于默认登录页、成功成功URL、没有权限URL，在 ShiroConfiguration 中已经配置）。<br>在 user 页面上，不同用户会根据权限不同显示不同的内容，下面的修改操作也已经有文字说明，更换账号测试便知。</p>
<p>然后我们在实际项目中：不但要在页面上控制不同权限隐藏或将某些操作设置为不可用状态，还要在实际上控制那个操作背后的请求是真的不可以使用的。（例如：页面上的修改<br>按钮已经灰化了，而我知道了修改按钮正常情况下点击会触发的请求，此时我直接模拟这个修改请求，应当是没有权限的才对，这样才算是真正的控制了权限。）</p>
<hr>
<p>附：<br><strong> Filter Chain定义说明 </strong><br>1、一个URL可以配置多个Filter，使用逗号分隔<br>2、当设置多个过滤器时，全部验证通过，才视为通过<br>3、部分过滤器可指定参数，如perms，roles</p>
<p><strong> Shiro内置的FilterChain </strong></p>
<p>Filter Name  Class</p>
<p>anon</p>
<p>org.apache.shiro.web.filter.authc.AnonymousFilter</p>
<p>authc</p>
<p>org.apache.shiro.web.filter.authc.FormAuthenticationFilter</p>
<p>authcBasic</p>
<p>org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter</p>
<p>perms</p>
<p>org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter</p>
<p>port</p>
<p>org.apache.shiro.web.filter.authz.PortFilter</p>
<p>rest</p>
<p>org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter</p>
<p>roles</p>
<p>org.apache.shiro.web.filter.authz.RolesAuthorizationFilter</p>
<p>ssl</p>
<p>org.apache.shiro.web.filter.authz.SslFilter</p>
<p>user</p>
<p>org.apache.shiro.web.filter.authc.UserFilter</p>

        
        </div>
        <footer class="article-footer">
            <div class="share-container">


    <div class="bdsharebuttonbox">
    <a href="#" class="bds_more" data-cmd="more">分享到：</a>
    <a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间">QQ空间</a>
    <a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博">新浪微博</a>
    <a href="#" class="bds_tqq" data-cmd="tqq" title="分享到腾讯微博">腾讯微博</a>
    <a href="#" class="bds_renren" data-cmd="renren" title="分享到人人网">人人网</a>
    <a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信">微信</a>
</div>
<script>
window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{"bdSize":16}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];
</script>
<style>
    .bdshare_popup_box {
        border-radius: 4px;
        border: #e1e1e1 solid 1px;
    }
    .bdshare-button-style0-16 a,
    .bdshare-button-style0-16 .bds_more {
        padding-left: 20px;
        margin: 6px 10px 6px 0;
    }
    .bdshare_dialog_list a,
    .bdshare_popup_list a,
    .bdshare_popup_bottom a {
        font-family: 'Microsoft Yahei';
    }
    .bdshare_popup_top {
        display: none;
    }
    .bdshare_popup_bottom {
        height: auto;
        padding: 5px;
    }
</style>


</div>

            
    
        <a href="https://www.itchina.top/2018/04/20/Spring Boot Shiro 权限管理/#comments" id="sourceId::2018/04/20/Spring Boot Shiro 权限管理/" class="article-comment-link cy_cmt_count">评论</a>
    

        </footer>
    </div>
    
</article>



    <article id="post-Spring Boot Servlet" class="article article-type-post" itemscope itemprop="blogPost">
    <div class="article-inner">
        
        
            <header class="article-header">
                
    
        <h1 itemprop="name">
            <a class="article-title" href="/2018/04/20/Spring Boot Servlet/">Spring Boot Servlet</a>
        </h1>
    

                
                    <div class="article-meta">
                        
    <div class="article-date">
        <i class="fa fa-calendar"></i>
        <a href="/2018/04/20/Spring Boot Servlet/">
            <time datetime="2018-04-19T16:34:21.432Z" itemprop="datePublished">2018-04-20</time>
        </a>
    </div>


                        
    <div class="article-category">
    	<i class="fa fa-folder"></i>
        <a class="article-category-link" href="/categories/Spring/">Spring</a>
    </div>

                        
    <div class="article-tag">
        <i class="fa fa-tag"></i>
        <a class="tag-link" href="/tags/spring/">spring</a>
    </div>

                    </div>
                
            </header>
        
        
        <div class="article-entry" itemprop="articleBody">
        
            
            <p>上一篇我们对如何创建Controller 来响应JSON 以及如何显示数据到页面中，已经有了初步的了解。<br>Web开发使用 Controller 基本上可以完成大部分需求，但是我们还可能会用到 Servlet、Filter、Listener、Interceptor<br>等等。</p>
<p>当使用Spring-Boot时，嵌入式Servlet容器通过扫描注解的方式注册Servlet、Filter和Servlet规范的所有监听器（如HttpSes<br>sionListener监听器）。<br>Spring boot 的主 Servlet 为 DispatcherServlet，其默认的url-<br>pattern为“/”。也许我们在应用中还需要定义更多的Servlet，该如何使用SpringBoot来完成呢？</p>
<p>在spring boot中添加自己的Servlet有两种方法，代码注册Servlet和注解自动注册（Filter和Listener也是如此）。<br>一、代码注册通过ServletRegistrationBean、 FilterRegistrationBean 和<br>ServletListenerRegistrationBean 获得控制。<br>也可以通过实现 ServletContextInitializer 接口直接注册。</p>
<p>二、在 SpringBootApplication 上使用@ServletComponentScan 注解后，Servlet、Filter、Listener<br>可以直接通过 @WebServlet、@WebFilter、@WebListener 注解自动注册，无需其他代码。</p>
<p><strong> 通过代码注册Servlet示例代码： </strong></p>
<p>SpringBootSampleApplication. <a href="http://lib.csdn.net/base/17" target="_blank" rel="noopener"> Java </a></p>
<pre><code>package org.springboot.sample;

import org.springboot.sample.servlet.MyServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.DispatcherServlet;

@SpringBootApplication
public class SpringBootSampleApplication {

    /**
     * 使用代码注册Servlet（不需要@ServletComponentScan注解）
     *
     * @return
     * @author SHANHY
     * @create  2016年1月6日
     */
    @Bean
    public ServletRegistrationBean servletRegistrationBean() {
        return new ServletRegistrationBean(new MyServlet(), &quot;/xs/*&quot;);// ServletName默认值为首字母小写，即myServlet
    }

    public static void main(String[] args) {
        SpringApplication.run(SpringBootSampleApplication.class, args);
    }
}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
</ul>
<p>MyServlet.java</p>
<pre><code>package org.springboot.sample.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet
 *
 * @author   单红宇(365384722)
 * @myblog  http://blog.csdn.net/catoop/
 * @create    2016年1月6日
 */
//@WebServlet(urlPatterns=&quot;/xs/*&quot;, description=&quot;Servlet的说明&quot;)
public class MyServlet extends HttpServlet{

    private static final long serialVersionUID = -8685285401859800066L;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(&quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;doGet()&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&quot;);
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(&quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;doPost()&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&quot;);
        resp.setContentType(&quot;text/html&quot;);  
        PrintWriter out = resp.getWriter();  
        out.println(&quot;&lt;html&gt;&quot;);  
        out.println(&quot;&lt;head&gt;&quot;);  
        out.println(&quot;&lt;title&gt;Hello World&lt;/title&gt;&quot;);  
        out.println(&quot;&lt;/head&gt;&quot;);  
        out.println(&quot;&lt;body&gt;&quot;);  
        out.println(&quot;&lt;h1&gt;大家好，我的名字叫Servlet&lt;/h1&gt;&quot;);  
        out.println(&quot;&lt;/body&gt;&quot;);  
        out.println(&quot;&lt;/html&gt;&quot;); 
    }

}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
</ul>
<p><strong> 使用注解注册Servlet示例代码 </strong></p>
<p>SpringBootSampleApplication.java</p>
<pre><code>package org.springboot.sample;

import org.springboot.sample.servlet.MyServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.embedded.ServletRegistrationBean;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.DispatcherServlet;

@SpringBootApplication
@ServletComponentScan
public class SpringBootSampleApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootSampleApplication.class, args);
    }
}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
</ul>
<p>MyServlet2.java</p>
<pre><code>package org.springboot.sample.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet
 *
 * @author   单红宇(365384722)
 * @myblog  http://blog.csdn.net/catoop/
 * @create    2016年1月6日
 */
@WebServlet(urlPatterns=&quot;/xs/myservlet&quot;, description=&quot;Servlet的说明&quot;) // 不指定name的情况下，name默认值为类全路径，即org.springboot.sample.servlet.MyServlet2
public class MyServlet2 extends HttpServlet{

    private static final long serialVersionUID = -8685285401859800066L;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(&quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;doGet2()&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&quot;);
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println(&quot;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;doPost2()&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&quot;);
        resp.setContentType(&quot;text/html&quot;);  
        PrintWriter out = resp.getWriter();  
        out.println(&quot;&lt;html&gt;&quot;);  
        out.println(&quot;&lt;head&gt;&quot;);  
        out.println(&quot;&lt;title&gt;Hello World&lt;/title&gt;&quot;);  
        out.println(&quot;&lt;/head&gt;&quot;);  
        out.println(&quot;&lt;body&gt;&quot;);  
        out.println(&quot;&lt;h1&gt;大家好，我的名字叫Servlet2&lt;/h1&gt;&quot;);  
        out.println(&quot;&lt;/body&gt;&quot;);  
        out.println(&quot;&lt;/html&gt;&quot;); 
    }

}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
<li>46 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
<li>46 </li>
</ul>
<p>使用 @WebServlet 注解，其中可以设置一些属性。</p>
<p>有个问题：DispatcherServlet 默认拦截“/”，MyServlet 拦截“/xs/*”，MyServlet2<br>拦截“/xs/myservlet”，那么在我们访问 <a href="http://localhost:8080/xs/myservlet" target="_blank" rel="noopener"> http://localhost:8080/xs/myservlet
</a> 的时候系统会怎么处理呢？如果访问 <a href="http://localhost:8080/xs/abc" target="_blank" rel="noopener"><br>http://localhost:8080/xs/abc </a><br>的时候又是什么结果呢？这里就不给大家卖关子了，其结果是“匹配的优先级是从精确到模糊，复合条件的Servlet并不会都执行”</p>
<p>既然系统DispatcherServlet<br>默认拦截“/”，那么我们是否能做修改呢，答案是肯定的，我们在SpringBootSampleApplication中添加代码：</p>
<pre><code>/**
 * 修改DispatcherServlet默认配置
 *
 * @param dispatcherServlet
 * @return
 * @author SHANHY
 * @create  2016年1月6日
 */
@Bean
public ServletRegistrationBean dispatcherRegistration(DispatcherServlet dispatcherServlet) {
    ServletRegistrationBean registration = new ServletRegistrationBean(dispatcherServlet);
    registration.getUrlMappings().clear();
    registration.addUrlMappings(&quot;*.do&quot;);
    registration.addUrlMappings(&quot;*.json&quot;);
    return registration;
}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
</ul>
<p>当然，这里可以对DispatcherServlet做很多修改，并非只是UrlMappings。</p>

        
        </div>
        <footer class="article-footer">
            <div class="share-container">


    <div class="bdsharebuttonbox">
    <a href="#" class="bds_more" data-cmd="more">分享到：</a>
    <a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间">QQ空间</a>
    <a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博">新浪微博</a>
    <a href="#" class="bds_tqq" data-cmd="tqq" title="分享到腾讯微博">腾讯微博</a>
    <a href="#" class="bds_renren" data-cmd="renren" title="分享到人人网">人人网</a>
    <a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信">微信</a>
</div>
<script>
window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{"bdSize":16}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];
</script>
<style>
    .bdshare_popup_box {
        border-radius: 4px;
        border: #e1e1e1 solid 1px;
    }
    .bdshare-button-style0-16 a,
    .bdshare-button-style0-16 .bds_more {
        padding-left: 20px;
        margin: 6px 10px 6px 0;
    }
    .bdshare_dialog_list a,
    .bdshare_popup_list a,
    .bdshare_popup_bottom a {
        font-family: 'Microsoft Yahei';
    }
    .bdshare_popup_top {
        display: none;
    }
    .bdshare_popup_bottom {
        height: auto;
        padding: 5px;
    }
</style>


</div>

            
    
        <a href="https://www.itchina.top/2018/04/20/Spring Boot Servlet/#comments" id="sourceId::2018/04/20/Spring Boot Servlet/" class="article-comment-link cy_cmt_count">评论</a>
    

        </footer>
    </div>
    
</article>



    <article id="post-Spring Boot MyBatis 连接数据库" class="article article-type-post" itemscope itemprop="blogPost">
    <div class="article-inner">
        
        
            <header class="article-header">
                
    
        <h1 itemprop="name">
            <a class="article-title" href="/2018/04/20/Spring Boot MyBatis 连接数据库/">Spring Boot MyBatis 连接数据库</a>
        </h1>
    

                
                    <div class="article-meta">
                        
    <div class="article-date">
        <i class="fa fa-calendar"></i>
        <a href="/2018/04/20/Spring Boot MyBatis 连接数据库/">
            <time datetime="2018-04-19T16:34:21.432Z" itemprop="datePublished">2018-04-20</time>
        </a>
    </div>


                        
    <div class="article-category">
    	<i class="fa fa-folder"></i>
        <a class="article-category-link" href="/categories/Spring/">Spring</a>
    </div>

                        
    <div class="article-tag">
        <i class="fa fa-tag"></i>
        <a class="tag-link" href="/tags/mybatis/">mybatis</a>, <a class="tag-link" href="/tags/spring/">spring</a>
    </div>

                    </div>
                
            </header>
        
        
        <div class="article-entry" itemprop="articleBody">
        
            
            <p>最近比较忙，没来得及抽时间把MyBatis的集成发出来，其实mybatis官网在2015年11月底就已经发布了对SpringBoot集成的Release版本<br>，Github上有代码： <a href="https://github.com/mybatis/mybatis-spring-boot" target="_blank" rel="noopener"> https://github.com/mybatis/mybatis-spring-boot
</a><br>前面对JPA和JDBC连接 <a href="http://lib.csdn.net/base/14" target="_blank" rel="noopener"> 数据库 </a> 做了说明，本文也是参考官方的代码做个总结。</p>
<p>先说个题外话，SpringBoot默认使用 org.apache.tomcat.jdbc.pool.DataSource<br>现在有个叫 HikariCP 的JDBC连接池组件，据说其性能比常用的 c3p0、tomcat、bone、vibur 这些要高很多。<br>我打算把工程中的DataSource变更为HirakiDataSource，做法很简单：<br>首先在application.properties配置文件中指定dataSourceType</p>
<pre><code>spring.datasource.type=com.zaxxer.hikari.HikariDataSource
</code></pre><ul>
<li>1 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
</ul>
<p>然后在pom中添加Hikari的依赖</p>
<pre><code>&lt;dependency&gt;
    &lt;groupId&gt;com.zaxxer&lt;/groupId&gt;
    &lt;artifactId&gt;HikariCP&lt;/artifactId&gt;
    &lt;!-- 版本号可以不用指定，Spring Boot会选用合适的版本 --&gt;
&lt;/dependency&gt;
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
</ul>
<p>言归正传，下面说在Spring Boot中配置MyBatis。<br>关于在Spring Boot中集成MyBatis，可以选用基于注解的方式，也可以选择xml文件配置的方式。通过对两者进行实际的使用，还是建议使用XML的方式<br>（官方也建议使用XML）。</p>
<p>下面将介绍通过xml的方式来实现查询，其次会简单说一下注解方式，最后会附上分页插件（PageHelper）的集成。</p>
<h3 id="一、通过xml配置文件方式"><a href="#一、通过xml配置文件方式" class="headerlink" title="一、通过xml配置文件方式"></a>一、通过xml配置文件方式</h3><h4 id="1、添加pom依赖"><a href="#1、添加pom依赖" class="headerlink" title="1、添加pom依赖"></a>1、添加pom依赖</h4><pre><code>&lt;dependency&gt;
    &lt;groupId&gt;org.mybatis.spring.boot&lt;/groupId&gt;
    &lt;artifactId&gt;mybatis-spring-boot-starter&lt;/artifactId&gt;
    &lt;!-- 请不要使用1.0.0版本，因为还不支持拦截器插件，1.0.1-SNAPSHOT 是博主写帖子时候的版本，大家使用最新版本即可 --&gt;
    &lt;version&gt;1.0.1-SNAPSHOT&lt;/version&gt;
&lt;/dependency&gt;
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
</ul>
<h4 id="2、创建接口Mapper（不是类）和对应的Mapper-xml文件"><a href="#2、创建接口Mapper（不是类）和对应的Mapper-xml文件" class="headerlink" title="2、创建接口Mapper（不是类）和对应的Mapper.xml文件"></a>2、创建接口Mapper（不是类）和对应的Mapper.xml文件</h4><p>定义相关方法，注意方法名称要和Mapper.xml文件中的id一致，这样会自动对应上<br>StudentMapper. <a href="http://lib.csdn.net/base/17" target="_blank" rel="noopener"> Java </a></p>
<pre><code>package org.springboot.sample.mapper;

import java.util.List;

import org.springboot.sample.entity.Student;

/**
 * StudentMapper，映射SQL语句的接口，无逻辑实现
 *
 * @author 单红宇(365384722)
 * @myblog http://blog.csdn.net/catoop/
 * @create 2016年1月20日
 */
public interface StudentMapper extends MyMapper&lt;Student&gt; {

    List&lt;Student&gt; likeName(String name);

    Student getById(int id);

    String getNameById(int id);

}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
</ul>
<p>MyMapper.java</p>
<pre><code>package org.springboot.sample.config.mybatis;

import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.common.MySqlMapper;

/**
 * 被继承的Mapper，一般业务Mapper继承它
 *
 */
public interface MyMapper&lt;T&gt; extends Mapper&lt;T&gt;, MySqlMapper&lt;T&gt; {
    //TODO
    //FIXME 特别注意，该接口不能被扫描到，否则会出错
}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
</ul>
<p>StudentMapper.xml</p>
<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;!DOCTYPE mapper PUBLIC &quot;-//mybatis.org//DTD Mapper 3.0//EN&quot; 
&quot;http://mybatis.org/dtd/mybatis-3-mapper.dtd&quot;&gt;
&lt;mapper namespace=&quot;org.springboot.sample.mapper.StudentMapper&quot;&gt;

    &lt;!-- type为实体类Student，包名已经配置，可以直接写类名 --&gt;
    &lt;resultMap id=&quot;stuMap&quot; type=&quot;Student&quot;&gt;
        &lt;id property=&quot;id&quot; column=&quot;id&quot; /&gt;
        &lt;result property=&quot;name&quot; column=&quot;name&quot; /&gt;
        &lt;result property=&quot;sumScore&quot; column=&quot;score_sum&quot; /&gt;
        &lt;result property=&quot;avgScore&quot; column=&quot;score_avg&quot; /&gt;
        &lt;result property=&quot;age&quot; column=&quot;age&quot; /&gt;
    &lt;/resultMap&gt;

    &lt;select id=&quot;getById&quot; resultMap=&quot;stuMap&quot; resultType=&quot;Student&quot;&gt;
        SELECT *
        FROM STUDENT
        WHERE ID = #{id}
    &lt;/select&gt;

    &lt;select id=&quot;likeName&quot; resultMap=&quot;stuMap&quot; parameterType=&quot;string&quot; resultType=&quot;list&quot;&gt;
        SELECT *
        FROM STUDENT
        WHERE NAME LIKE CONCAT(&apos;%&apos;,#{name},&apos;%&apos;)
    &lt;/select&gt;

    &lt;select id=&quot;getNameById&quot; resultType=&quot;string&quot;&gt;
        SELECT NAME
        FROM STUDENT
        WHERE ID = #{id}
    &lt;/select&gt;


&lt;/mapper&gt; 
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
</ul>
<h4 id="3、实体类"><a href="#3、实体类" class="headerlink" title="3、实体类"></a>3、实体类</h4><pre><code>package org.springboot.sample.entity;

import java.io.Serializable;

/**
 * 学生实体
 *
 * @author   单红宇(365384722)
 * @myblog  http://blog.csdn.net/catoop/
 * @create    2016年1月12日
 */
public class Student implements Serializable{

    private static final long serialVersionUID = 2120869894112984147L;

    private int id;
    private String name;
    private String sumScore;
    private String avgScore;
    private int age;

    // get set 方法省略

}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
</ul>
<h4 id="4、修改application-properties-配置文件"><a href="#4、修改application-properties-配置文件" class="headerlink" title="4、修改application.properties 配置文件"></a>4、修改application.properties 配置文件</h4><pre><code>mybatis.mapper-locations=classpath*:org/springboot/sample/mapper/sql/mysql/*Mapper.xml
mybatis.type-aliases-package=org.springboot.sample.entity
</code></pre><ul>
<li>1 </li>
<li>2 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
</ul>
<h4 id="5、在Controller或Service调用方法测试"><a href="#5、在Controller或Service调用方法测试" class="headerlink" title="5、在Controller或Service调用方法测试"></a>5、在Controller或Service调用方法测试</h4><pre><code>@Autowired
private StudentMapper stuMapper;

@RequestMapping(&quot;/likeName&quot;)
public List&lt;Student&gt; likeName(@RequestParam String name){
    return stuMapper.likeName(name);
}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
</ul>
<h3 id="二、使用注解方式"><a href="#二、使用注解方式" class="headerlink" title="二、使用注解方式"></a>二、使用注解方式</h3><p>查看官方git上的代码使用注解方式，配置上很简单，使用上要对注解多做了解。至于xml和注解这两种哪种方法好，众口难调还是要看每个人吧。</p>
<h4 id="1、启动类（我的）中添加-MapperScan注解"><a href="#1、启动类（我的）中添加-MapperScan注解" class="headerlink" title="1、启动类（我的）中添加@MapperScan注解"></a>1、启动类（我的）中添加@MapperScan注解</h4><pre><code>@SpringBootApplication
@MapperScan(&quot;sample.mybatis.mapper&quot;)
public class SampleMybatisApplication implements CommandLineRunner {

    @Autowired
    private CityMapper cityMapper;

    public static void main(String[] args) {
        SpringApplication.run(SampleMybatisApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        System.out.println(this.cityMapper.findByState(&quot;CA&quot;));
    }

}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
</ul>
<h4 id="2、在接口上使用注解定义CRUD语句"><a href="#2、在接口上使用注解定义CRUD语句" class="headerlink" title="2、在接口上使用注解定义CRUD语句"></a>2、在接口上使用注解定义CRUD语句</h4><pre><code>package sample.mybatis.mapper;

import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import sample.mybatis.domain.City;

/**
 * @author Eddú Meléndez
 */
public interface CityMapper {

    @Select(&quot;SELECT * FROM CITY WHERE state = #{state}&quot;)
    City findByState(@Param(&quot;state&quot;) String state);

}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
</ul>
<p>其中City就是一个普通Java类。<br>关于MyBatis的注解，有篇文章讲的很清楚，可以参考： <a href="http://blog.csdn.net/luanlouis/article/details/35780175" target="_blank" rel="noopener"><br>http://blog.csdn.net/luanlouis/article/details/35780175
</a></p>
<h3 id="三、集成分页插件"><a href="#三、集成分页插件" class="headerlink" title="三、集成分页插件"></a>三、集成分页插件</h3><p>这里与其说集成分页插件，不如说是介绍如何集成一个plugin。MyBatis提供了拦截器接口，我们可以实现自己的拦截器，将其作为一个plugin装入到Sql<br>SessionFactory中。<br>Github上有位开发者写了一个分页插件，我觉得使用起来还可以，挺方便的。<br>Github项目地址： <a href="https://github.com/pagehelper/Mybatis-PageHelper" target="_blank" rel="noopener"> https://github.com/pagehelper/Mybatis-PageHelper
</a></p>
<p>下面简单介绍下：<br>首先要说的是，Spring在依赖注入bean的时候，会把所有实现MyBatis中Interceptor接口的所有类都注入到SqlSessionFactory<br>中，作为plugin存在。既然如此，我们集成一个plugin便很简单了，只需要使用@Bean创建PageHelper对象即可。</p>
<h4 id="1、添加pom依赖-1"><a href="#1、添加pom依赖-1" class="headerlink" title="1、添加pom依赖"></a>1、添加pom依赖</h4><pre><code>&lt;dependency&gt;
    &lt;groupId&gt;com.github.pagehelper&lt;/groupId&gt;
    &lt;artifactId&gt;pagehelper&lt;/artifactId&gt;
    &lt;version&gt;4.1.0&lt;/version&gt;
&lt;/dependency&gt;
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
</ul>
<h4 id="2、新增MyBatisConfiguration-java"><a href="#2、新增MyBatisConfiguration-java" class="headerlink" title="2、新增MyBatisConfiguration.java"></a>2、新增MyBatisConfiguration.java</h4><pre><code>package org.springboot.sample.config;

import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.github.pagehelper.PageHelper;

/**
 * MyBatis 配置
 *
 * @author 单红宇(365384722)
 * @myblog http://blog.csdn.net/catoop/
 * @create 2016年1月21日
 */
@Configuration
public class MyBatisConfiguration {

    private static final Logger logger = LoggerFactory.getLogger(MyBatisConfiguration.class);

    @Bean
    public PageHelper pageHelper() {
        logger.info(&quot;注册MyBatis分页插件PageHelper&quot;);
        PageHelper pageHelper = new PageHelper();
        Properties p = new Properties();
        p.setProperty(&quot;offsetAsPageNum&quot;, &quot;true&quot;);
        p.setProperty(&quot;rowBoundsWithCount&quot;, &quot;true&quot;);
        p.setProperty(&quot;reasonable&quot;, &quot;true&quot;);
        pageHelper.setProperties(p);
        return pageHelper;
    }

}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
</ul>
<h4 id="3、分页查询测试"><a href="#3、分页查询测试" class="headerlink" title="3、分页查询测试"></a>3、分页查询测试</h4><pre><code>@RequestMapping(&quot;/likeName&quot;)
public List&lt;Student&gt; likeName(@RequestParam String name){
    PageHelper.startPage(1, 1);
    return stuMapper.likeName(name);
}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
</ul>
<p>更多参数使用方法，详见PageHelper说明文档（上面的Github地址）。</p>

        
        </div>
        <footer class="article-footer">
            <div class="share-container">


    <div class="bdsharebuttonbox">
    <a href="#" class="bds_more" data-cmd="more">分享到：</a>
    <a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间">QQ空间</a>
    <a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博">新浪微博</a>
    <a href="#" class="bds_tqq" data-cmd="tqq" title="分享到腾讯微博">腾讯微博</a>
    <a href="#" class="bds_renren" data-cmd="renren" title="分享到人人网">人人网</a>
    <a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信">微信</a>
</div>
<script>
window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{"bdSize":16}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];
</script>
<style>
    .bdshare_popup_box {
        border-radius: 4px;
        border: #e1e1e1 solid 1px;
    }
    .bdshare-button-style0-16 a,
    .bdshare-button-style0-16 .bds_more {
        padding-left: 20px;
        margin: 6px 10px 6px 0;
    }
    .bdshare_dialog_list a,
    .bdshare_popup_list a,
    .bdshare_popup_bottom a {
        font-family: 'Microsoft Yahei';
    }
    .bdshare_popup_top {
        display: none;
    }
    .bdshare_popup_bottom {
        height: auto;
        padding: 5px;
    }
</style>


</div>

            
    
        <a href="https://www.itchina.top/2018/04/20/Spring Boot MyBatis 连接数据库/#comments" id="sourceId::2018/04/20/Spring Boot MyBatis 连接数据库/" class="article-comment-link cy_cmt_count">评论</a>
    

        </footer>
    </div>
    
</article>



    <article id="post-Spring Boot JPA 连接数据库" class="article article-type-post" itemscope itemprop="blogPost">
    <div class="article-inner">
        
        
            <header class="article-header">
                
    
        <h1 itemprop="name">
            <a class="article-title" href="/2018/04/20/Spring Boot JPA 连接数据库/">Spring Boot JPA 连接数据库</a>
        </h1>
    

                
                    <div class="article-meta">
                        
    <div class="article-date">
        <i class="fa fa-calendar"></i>
        <a href="/2018/04/20/Spring Boot JPA 连接数据库/">
            <time datetime="2018-04-19T16:34:21.431Z" itemprop="datePublished">2018-04-20</time>
        </a>
    </div>


                        
    <div class="article-category">
    	<i class="fa fa-folder"></i>
        <a class="article-category-link" href="/categories/Spring/">Spring</a>
    </div>

                        
    <div class="article-tag">
        <i class="fa fa-tag"></i>
        <a class="tag-link" href="/tags/jpa/">jpa</a>, <a class="tag-link" href="/tags/spring/">spring</a>
    </div>

                    </div>
                
            </header>
        
        
        <div class="article-entry" itemprop="articleBody">
        
            
            <p>本文将介绍如何在Spring Boot 工程中添加JPA作为持久化方式。</p>
<h3 id="修改-pom-xml-依赖"><a href="#修改-pom-xml-依赖" class="headerlink" title="修改 pom.xml 依赖"></a>修改 pom.xml 依赖</h3><p>与上一篇介绍的 jdbc 不同的是 spring-boot-starter-jdbc 修改为 spring-boot-starter-data-jpa<br>即可，当然 <a href="http://lib.csdn.net/base/14" target="_blank" rel="noopener"> 数据库 </a> 驱动包也是不可少的，如下：</p>
<pre><code>&lt;!-- MYSQL --&gt;
&lt;dependency&gt;
   &lt;groupId&gt;mysql&lt;/groupId&gt;
   &lt;artifactId&gt;mysql-connector-java&lt;/artifactId&gt;
&lt;/dependency&gt;
&lt;!-- Spring Boot JPA --&gt;
&lt;dependency&gt;
   &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
   &lt;artifactId&gt;spring-boot-starter-data-jpa&lt;/artifactId&gt;
&lt;/dependency&gt;
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
</ul>
<p>注意：如果你想JDBC和JPA可以一起使用，Spring Boot 是支持的，你只需要把JDBC和JPA的依赖都添加在pom.xml<br>中即可。无需其他特殊处理，有关JDBC的使用介绍请看上一篇 “ <a href="http://blog.csdn.net/catoop/article/details/50507516" target="_blank" rel="noopener"> Spring-Boot JDBC 连接数据库
</a> ”。</p>
<h3 id="修改属性配置文件"><a href="#修改属性配置文件" class="headerlink" title="修改属性配置文件"></a>修改属性配置文件</h3><p>在属性配置文件中添加 JPA 相关属性，注意这些并非必须，我们如果只添加dataSource 的 url\username\password\driver-<br>class-name 也可以正常使用，有关JPA的其他配置都是可选的。</p>
<pre><code>spring.jpa.database=
spring.jpa.show-sql=
spring.jpa.properties=
spring.jpa.generate-ddl=
spring.jpa.open-in-view=
spring.jpa.database-platform=
spring.jpa.hibernate.ddl-auto=
spring.data.jpa.repositories.enabled=
spring.jpa.hibernate.naming-strategy=
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
</ul>
<p>熟悉JPA的根据名字应基本知道这些分别的作用了。</p>
<p>传统上，JPA实体类在persistence.xml文件中指定的。使用Spring Boot，这个文件是没有必要的，因为它使用“实体扫描”，默认情况下主配置<br>@EnableAutoConfiguration 或 @SpringBootApplication 下面的所有包都将会被扫描。任何使用注解 @Entity,<br>@Embeddable 或 @MappedSuperclass 的类都将被管理。</p>
<h3 id="Java代码实例"><a href="#Java代码实例" class="headerlink" title="Java代码实例"></a>Java代码实例</h3><ul>
<li>一个接口 </li>
<li>一个Controller </li>
</ul>
<p>我们创建一个接口 IScoreDao. <a href="http://lib.csdn.net/base/17" target="_blank" rel="noopener"> Java </a> ，然后我们继承框架为我们提供好的接口<br>Repository 或 CrudRepository （CrudRepository 继承自<br>Repository），其中为我们提供了对数据库的基本操作方法。</p>
<pre><code>package org.springboot.sample.dao;

import java.util.List;

import javax.transaction.Transactional;

import org.springboot.sample.entity.Score;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;

public interface IScoreDao extends CrudRepository&lt;Score, Integer&gt; {

    @Transactional
    @Modifying
    @Query(&quot;update Score t set t.score = :score where t.id = :id&quot;)
    int updateScoreById(@Param(&quot;score&quot;) float score, @Param(&quot;id&quot;) int id);

    @Query(&quot;select t from Score t &quot;)
    List&lt;Score&gt; getList();

}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
</ul>
<p>注意，如果你其中使用了修改、新增、删除操作，则必须要在接口上面或者对应的方法上面添加 @Transactional 注解，否则会抛出异常。</p>
<p>实体类 Score.java</p>
<pre><code>package org.springboot.sample.entity;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

/**
 * 成绩
 *
 * @author 单红宇(365384722)
 * @myblog http://blog.csdn.net/catoop/
 * @create 2016年1月12日
 */
@Entity
@Table(name = &quot;score&quot;)
public class Score implements Serializable {

    private static final long serialVersionUID = 8127035730921338189L;

    @Id
    @GeneratedValue
    private int id;

    @Column(nullable = false, name=&quot;STUDENTID&quot;) // 这里说一下，我使用指定数据库列的时候，使用小写会不起作用，修改为大写便正常了。不知道为何，如果遇到一样问题的可以尝试下。
    private int stuId;

    @Column(nullable = false, name=&quot;SUBJECTNAME&quot;)
    private String subjectName;

    @Column(nullable = false)
    private float score;

    @Column(nullable = false, name=&quot;EXAMTIME&quot;)
    private Date examTime; 

    // 省去get、set 方法（占用文章空间）

}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
</ul>
<p>ScoreController.java</p>
<pre><code>package org.springboot.sample.controller;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springboot.sample.dao.IScoreDao;
import org.springboot.sample.entity.Score;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(&quot;/score&quot;)
public class ScoreController {

    private static final Logger logger = LoggerFactory.getLogger(ScoreController.class);

    @Autowired
    private IScoreDao scoreService;

    @RequestMapping(&quot;/scoreList&quot;)
    public List&lt;Score&gt; getScoreList(){
        logger.info(&quot;从数据库读取Score集合&quot;);
        // 测试更新数据库
        logger.info(&quot;更新的行数：&quot; + scoreService.updateScoreById(88.8f, 2));
        scoreService.delete(23);

        return scoreService.getList();
    }
}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
</ul>
<p>然后在浏览器访问地址： <a href="http://localhost:8080/myspringboot/score/scoreList" target="_blank" rel="noopener"> http://localhost:8080/myspringboot/score/scoreList
</a> 测试。</p>
<hr>
<p>最后要说明的是，Spring 会自动为我们继承CrudRepository接口的接口创建实现类。我们只需要在使用的时候直接使用注解 @Autowired<br>注入即可（IScoreDao 接口上也没有必要增加 @Component 、 @Repository 等注解）。<br>还有，我这里为了简单起见，直接将操作数据库的在Controller中使用，实际项目中，是不建议这样做的，IScoreDao<br>的所属角色是数据库持久，我们还应当有 Service（如ScoreService） 来调用 IScoreDao 的方法，然后在Controller 中调用<br>Service 中的方法。原因是因为，我们数据库访问层，都是接口定义方法，上面注解注入SQL和参数，没有具体的代码逻辑处理。如果我们想在执行SQL之前或之后<br>执行逻辑处理，只能在 Service 中或者Controller（不建议）中。<br>我们严格按照这种方式去做（持久层只与SQL有关，通过接口定义无逻辑处理），这样才是彻彻底底的持久层。越严格的规范制度，在某种程度上来说其实越有利于代码的管理<br>和项目代码的迭代发展。</p>
<p>当然，如果你实在想要实现自己的 class 实现类，下面会附上一个实例代码，在此之前，我们先看一个图片：<br><img src="https://img-blog.csdn.net/20160113115006598" alt="这里写图片描述"></p>
<p>这个图是Spring 使用动态代理创建的接口实例，可以看出，其使用的是 SimpleJpaRepository 类，所以如果我们实现自己的<br>Repository ，可以扩展 SimpleJpaRepository 并 实现自己的 factory-class 入手，这里不做详解。注意凡事实现<br>Repository 接口的实现类都不需要添加 @Repository 注解，否则你会遇到问题。</p>
<p>本文介绍JPA 相比上一篇关于JDBC 的介绍增加的文件工程截图为：<br><img src="https://img-blog.csdn.net/20160113093520388" alt="工程结构截图"></p>
<p>熟悉其中一种持久数据的方法后，其他类似的都大同小异。</p>

        
        </div>
        <footer class="article-footer">
            <div class="share-container">


    <div class="bdsharebuttonbox">
    <a href="#" class="bds_more" data-cmd="more">分享到：</a>
    <a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间">QQ空间</a>
    <a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博">新浪微博</a>
    <a href="#" class="bds_tqq" data-cmd="tqq" title="分享到腾讯微博">腾讯微博</a>
    <a href="#" class="bds_renren" data-cmd="renren" title="分享到人人网">人人网</a>
    <a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信">微信</a>
</div>
<script>
window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{"bdSize":16}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];
</script>
<style>
    .bdshare_popup_box {
        border-radius: 4px;
        border: #e1e1e1 solid 1px;
    }
    .bdshare-button-style0-16 a,
    .bdshare-button-style0-16 .bds_more {
        padding-left: 20px;
        margin: 6px 10px 6px 0;
    }
    .bdshare_dialog_list a,
    .bdshare_popup_list a,
    .bdshare_popup_bottom a {
        font-family: 'Microsoft Yahei';
    }
    .bdshare_popup_top {
        display: none;
    }
    .bdshare_popup_bottom {
        height: auto;
        padding: 5px;
    }
</style>


</div>

            
    
        <a href="https://www.itchina.top/2018/04/20/Spring Boot JPA 连接数据库/#comments" id="sourceId::2018/04/20/Spring Boot JPA 连接数据库/" class="article-comment-link cy_cmt_count">评论</a>
    

        </footer>
    </div>
    
</article>



    <article id="post-Spring Boot JDBC 连接数据库" class="article article-type-post" itemscope itemprop="blogPost">
    <div class="article-inner">
        
        
            <header class="article-header">
                
    
        <h1 itemprop="name">
            <a class="article-title" href="/2018/04/20/Spring Boot JDBC 连接数据库/">Spring Boot JDBC 连接数据库</a>
        </h1>
    

                
                    <div class="article-meta">
                        
    <div class="article-date">
        <i class="fa fa-calendar"></i>
        <a href="/2018/04/20/Spring Boot JDBC 连接数据库/">
            <time datetime="2018-04-19T16:34:21.430Z" itemprop="datePublished">2018-04-20</time>
        </a>
    </div>


                        
    <div class="article-category">
    	<i class="fa fa-folder"></i>
        <a class="article-category-link" href="/categories/Spring/">Spring</a>
    </div>

                        
                    </div>
                
            </header>
        
        
        <div class="article-entry" itemprop="articleBody">
        
            
            <p>文本将对在Spring Boot构建的Web应用中，基于 <a href="http://lib.csdn.net/base/14" target="_blank" rel="noopener"> MySQL </a> <a href="http://lib.csdn.net/base/14" target="_blank" rel="noopener"> 数据库
</a> 的几种数据库连接方式进行介绍。<br>包括JDBC、JPA、MyBatis、多数据源和事务。</p>
<h3 id="JDBC-连接数据库"><a href="#JDBC-连接数据库" class="headerlink" title="JDBC 连接数据库"></a>JDBC 连接数据库</h3><p>1、属性配置文件（application.properties）</p>
<pre><code>spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
</ul>
<p>如果使用JNDI，则可以替代 spring.datasource 的 url、username、password，如：</p>
<pre><code>spring.datasource.jndi-name=java:tomcat/datasources/example 
</code></pre><ul>
<li>1 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
</ul>
<p>值得一提的是，无论是Spring Boot默认的DataSource配置还是你自己的DataSource<br>bean，都会引用到外部属性文件中的属性配置。所以假设你自定义的DataSource<br>bean，你可以在定义bean时设置属性，也可以在属性文件中，以“spring.datasource.*”的方式使属性配置外部化。</p>
<p>2、pom.xml 配置maven依赖</p>
<pre><code>&lt;!-- MYSQL --&gt;
&lt;dependency&gt;
    &lt;groupId&gt;mysql&lt;/groupId&gt;
    &lt;artifactId&gt;mysql-connector-java&lt;/artifactId&gt;
 &lt;/dependency&gt;
 &lt;!-- Spring Boot JDBC --&gt;
 &lt;dependency&gt;
    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-starter-jdbc&lt;/artifactId&gt;
  &lt;/dependency&gt;
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
</ul>
<p>3、 <a href="http://lib.csdn.net/base/17" target="_blank" rel="noopener"> Java </a> 代码范例</p>
<p>StudentService.java</p>
<pre><code>package org.springboot.sample.service;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import org.springboot.sample.entity.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;

/**
 * Studeng Service
 *
 * @author   单红宇(365384722)
 * @myblog  http://blog.csdn.net/catoop/
 * @create    2016年1月12日
 */
@Service
public class StudentService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public List&lt;Student&gt; getList(){
        String sql = &quot;SELECT ID,NAME,SCORE_SUM,SCORE_AVG, AGE   FROM STUDENT&quot;;
        return (List&lt;Student&gt;) jdbcTemplate.query(sql, new RowMapper&lt;Student&gt;(){

            @Override
            public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
                Student stu = new Student();
                stu.setId(rs.getInt(&quot;ID&quot;));
                stu.setAge(rs.getInt(&quot;AGE&quot;));
                stu.setName(rs.getString(&quot;NAME&quot;));
                stu.setSumScore(rs.getString(&quot;SCORE_SUM&quot;));
                stu.setAvgScore(rs.getString(&quot;SCORE_AVG&quot;));
                return stu;
            }

        });
    }
}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
</ul>
<p>Student.java 实体类</p>
<pre><code>package org.springboot.sample.entity;

import java.io.Serializable;

/**
 * 学生实体
 *
 * @author   单红宇(365384722)
 * @myblog  http://blog.csdn.net/catoop/
 * @create    2016年1月12日
 */
public class Student implements Serializable{

    private static final long serialVersionUID = 2120869894112984147L;

    private int id;
    private String name;
    private String sumScore;
    private String avgScore;
    private int age;

    // 节省文章长度，get set 方法省略
}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
</ul>
<p>StudentController.java</p>
<pre><code>package org.springboot.sample.controller;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springboot.sample.entity.Student;
import org.springboot.sample.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(&quot;/stu&quot;)
public class StudentController {

    private static final Logger logger = LoggerFactory.getLogger(StudentController.class);

    @Autowired
    private StudentService studentService;

    @RequestMapping(&quot;/list&quot;)
    public List&lt;Student&gt; getStus(){
        logger.info(&quot;从数据库读取Student集合&quot;);
        return studentService.getList();
    }
}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
</ul>
<p>本文对工程添加文件后工程结构图：<br><img src="https://img-blog.csdn.net/20160112233020787" alt="这里写图片描述"></p>
<p>然后启动项目，访问地址： <a href="http://localhost:8080/myspringboot/stu/list" target="_blank" rel="noopener"> http://localhost:8080/myspringboot/stu/list
</a> 响应结果如下：</p>
<pre><code>[
{
id: 1,
name: &quot;小明&quot;,
sumScore: &quot;252&quot;,
avgScore: &quot;84&quot;,
age: 1
},
{
id: 2,
name: &quot;小王&quot;,
sumScore: &quot;187&quot;,
avgScore: &quot;62.3&quot;,
age: 1
},
{
id: 3,
name: &quot;莉莉&quot;,
sumScore: &quot;&quot;,
avgScore: &quot;&quot;,
age: 0
},
{
id: 4,
name: &quot;柱子&quot;,
sumScore: &quot;230&quot;,
avgScore: &quot;76.7&quot;,
age: 1
},
{
id: 5,
name: &quot;大毛&quot;,
sumScore: &quot;&quot;,
avgScore: &quot;&quot;,
age: 0
},
{
id: 6,
name: &quot;亮子&quot;,
sumScore: &quot;0&quot;,
avgScore: &quot;0&quot;,
age: 1
}
]
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
</ul>
<h3 id="连接池说明"><a href="#连接池说明" class="headerlink" title="连接池说明"></a>连接池说明</h3><p>Tomcat7之前，Tomcat本质应用了DBCP连接池技术来实现的JDBC数据源，但在Tomcat7之后，Tomcat提供了新的JDBC连接池方案，作为D<br>BCP的替换或备选方案，解决了许多之前使用DBCP的不利之处，并提高了性能。详细请参考： <a href="http://wiki.jikexueyuan.com/project/tomcat/tomcat-jdbc-pool.html" target="_blank" rel="noopener"><br>http://wiki.jikexueyuan.com/project/tomcat/tomcat-jdbc-pool.html
</a></p>
<p>Spring Boot为我们准备了最佳的数据库连接池方案，只需要在属性文件（例如application.properties）中配置需要的连接池参数即可。<br>我们使用Tomcat数据源连接池，需要依赖tomcat-jdbc，只要应用中添加了spring-boot-starter-jdbc 或 spring-<br>boot-starter-data-jpa依赖，则无需担心这点，因为将会自动添加 tomcat-jdbc 依赖。<br>假如我们想用其他方式的连接池技术，只要配置自己的DataSource bean，即可覆盖Spring Boot的自动配置。</p>
<p>请看我的数据源配置：</p>
<pre><code>spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

spring.datasource.max-idle=10
spring.datasource.max-wait=10000
spring.datasource.min-idle=5
spring.datasource.initial-size=5
spring.datasource.validation-query=SELECT 1
spring.datasource.test-on-borrow=false
spring.datasource.test-while-idle=true
spring.datasource.time-between-eviction-runs-millis=18800
spring.datasource.jdbc-interceptors=ConnectionState;SlowQueryReport(threshold=0)
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
</ul>
<p>配置过连接池的开发人员对这些属性的意义都有所认识。</p>
<p>我们打开DEBUG日志输出，logback.xml 中添加：</p>
<pre><code>&lt;logger name=&quot;org.springframework.boot&quot; level=&quot;DEBUG&quot;/&gt;
</code></pre><ul>
<li>1 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
</ul>
<p>然后启动项目，注意观察日志输出，如下图中会显示自动启用了连接池：<br><img src="https://img-blog.csdn.net/20160112233045748" alt="这里写图片描述"><br>我在上面的数据源配置中添加了过滤器，并设置了延迟时间为0（故意设置很低，实际项目中请修改）：</p>
<pre><code>spring.datasource.jdbc-interceptors=ConnectionState;SlowQueryReport(threshold=0)
</code></pre><ul>
<li>1 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
</ul>
<p>这个时候，我们访问 <a href="http://localhost:8080/myspringboot/stu/list" target="_blank" rel="noopener"> http://localhost:8080/myspringboot/stu/list
</a><br>观察日志，会发现框架自动将大于该时间的数据查询进行警告输出，如下：</p>
<pre><code>2016-01-12 23:27:06.710  WARN 17644 --- [nio-8080-exec-1] o.a.t.j.p.interceptor.SlowQueryReport    : Slow Query Report SQL=SELECT ID,NAME,SCORE_SUM,SCORE_AVG, AGE   FROM STUDENT; time=3 ms;
</code></pre><ul>
<li>1 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
</ul>

        
        </div>
        <footer class="article-footer">
            <div class="share-container">


    <div class="bdsharebuttonbox">
    <a href="#" class="bds_more" data-cmd="more">分享到：</a>
    <a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间">QQ空间</a>
    <a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博">新浪微博</a>
    <a href="#" class="bds_tqq" data-cmd="tqq" title="分享到腾讯微博">腾讯微博</a>
    <a href="#" class="bds_renren" data-cmd="renren" title="分享到人人网">人人网</a>
    <a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信">微信</a>
</div>
<script>
window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{"bdSize":16}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];
</script>
<style>
    .bdshare_popup_box {
        border-radius: 4px;
        border: #e1e1e1 solid 1px;
    }
    .bdshare-button-style0-16 a,
    .bdshare-button-style0-16 .bds_more {
        padding-left: 20px;
        margin: 6px 10px 6px 0;
    }
    .bdshare_dialog_list a,
    .bdshare_popup_list a,
    .bdshare_popup_bottom a {
        font-family: 'Microsoft Yahei';
    }
    .bdshare_popup_top {
        display: none;
    }
    .bdshare_popup_bottom {
        height: auto;
        padding: 5px;
    }
</style>


</div>

            
    
        <a href="https://www.itchina.top/2018/04/20/Spring Boot JDBC 连接数据库/#comments" id="sourceId::2018/04/20/Spring Boot JDBC 连接数据库/" class="article-comment-link cy_cmt_count">评论</a>
    

        </footer>
    </div>
    
</article>



    <article id="post-Spring Boot Controller" class="article article-type-post" itemscope itemprop="blogPost">
    <div class="article-inner">
        
        
            <header class="article-header">
                
    
        <h1 itemprop="name">
            <a class="article-title" href="/2018/04/20/Spring Boot Controller/">Spring Boot Controller</a>
        </h1>
    

                
                    <div class="article-meta">
                        
    <div class="article-date">
        <i class="fa fa-calendar"></i>
        <a href="/2018/04/20/Spring Boot Controller/">
            <time datetime="2018-04-19T16:34:21.429Z" itemprop="datePublished">2018-04-20</time>
        </a>
    </div>


                        
    <div class="article-category">
    	<i class="fa fa-folder"></i>
        <a class="article-category-link" href="/categories/Spring/">Spring</a>
    </div>

                        
    <div class="article-tag">
        <i class="fa fa-tag"></i>
        <a class="tag-link" href="/tags/spring/">spring</a>
    </div>

                    </div>
                
            </header>
        
        
        <div class="article-entry" itemprop="articleBody">
        
            
            <p>接上篇文章，HelloWorld程序中我们已经创建了一个HellController，里面包含了响应JSON的方法，本文针对Controller再做一下讲解<br>。</p>
<p>回顾上篇文章，我们在Controller中使用 @RestController 注解，该注解是Spring 4.0引入的。查看源码可知其包含了<br>@Controller 和 @ResponseBody 注解。我们可以理解为 @Controller的增强版。专门为响应内容式的 Controller<br>而设计的，可以直接响应对象为JSON。<br>而 @Controller 用来响应页面，spring-boot 支持多种模版引擎包括：<br>1，FreeMarker<br>2，Groovy<br>3，Thymeleaf （Spring 官网使用这个）<br>4，Velocity<br>5，JSP （貌似Spring Boot官方不推荐，STS创建的项目会在src/main/resources 下有个templates<br>目录，这里就是让我们放模版文件的，然后并没有生成诸如 SpringMVC 中的webapp目录）<br>不过本文还是选择大家都熟悉的JSP来举例，因为使用JSP与默认支持的模版需要特殊处理，所以拿来举例更好。</p>
<p>关于Controller<br>方法可以接收参数使用@RequestBody、@RequestParam、@ModelAttribute、JSONObject、HttpEntity<br>等方式，皆与Spring的使用一样，这里不做赘述。</p>
<p>下面我们来说一下如何使用 @Controller 实现响应JSP页面（与SpringMVC也是一样使用）。<br>创建PageController，编码如下：</p>
<pre><code>package org.springboot.sample.controller;

import java.util.Date;
import java.util.Map;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class PageController {

    // 从 application.properties 中读取配置，如取不到默认值为Hello Shanhy
    @Value(&quot;${application.hell:Hello Shanhy}&quot;)
    private String hello = &quot;Hello Shanhy&quot;;

    /**
     * 默认页&lt;br/&gt;
     * @RequestMapping(&quot;/&quot;) 和 @RequestMapping 是有区别的
     * 如果不写参数，则为全局默认页，加入输入404页面，也会自动访问到这个页面。
     * 如果加了参数“/”，则只认为是根页面。
     *
     * @return
     * @author SHANHY
     * @create  2016年1月5日
     */
    @RequestMapping(value = {&quot;/&quot;,&quot;/index&quot;})
    public String index(Map&lt;String, Object&gt; model){
        // 直接返回字符串，框架默认会去 spring.view.prefix 目录下的 （index拼接spring.view.suffix）页面
        // 本例为 /WEB-INF/jsp/index.jsp
        model.put(&quot;time&quot;, new Date());
        model.put(&quot;message&quot;, this.hello);
        return &quot;index&quot;;
    }

    /**
     * 响应到JSP页面page1
     *
     * @return
     * @author SHANHY
     * @create  2016年1月5日
     */
    @RequestMapping(&quot;/page1&quot;)
    public ModelAndView page1(){
        // 页面位置 /WEB-INF/jsp/page/page.jsp
        ModelAndView mav = new ModelAndView(&quot;page/page1&quot;);
        mav.addObject(&quot;content&quot;, hello);
        return mav;
    }

    /**
     * 响应到JSP页面page1（可以直接使用Model封装内容，直接返回页面字符串）
     *
     * @return
     * @author SHANHY
     * @create  2016年1月5日
     */
    @RequestMapping(&quot;/page2&quot;)
    public String page2(Model model){
        // 页面位置 /WEB-INF/jsp/page/page.jsp
        model.addAttribute(&quot;content&quot;, hello + &quot;（第二种）&quot;);
        return &quot;page/page1&quot;;
    }
}
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
<li>46 </li>
<li>47 </li>
<li>48 </li>
<li>49 </li>
<li>50 </li>
<li>51 </li>
<li>52 </li>
<li>53 </li>
<li>54 </li>
<li>55 </li>
<li>56 </li>
<li>57 </li>
<li>58 </li>
<li>59 </li>
<li>60 </li>
<li>61 </li>
<li>62 </li>
<li>63 </li>
<li>64 </li>
<li>65 </li>
<li>66 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
<li>46 </li>
<li>47 </li>
<li>48 </li>
<li>49 </li>
<li>50 </li>
<li>51 </li>
<li>52 </li>
<li>53 </li>
<li>54 </li>
<li>55 </li>
<li>56 </li>
<li>57 </li>
<li>58 </li>
<li>59 </li>
<li>60 </li>
<li>61 </li>
<li>62 </li>
<li>63 </li>
<li>64 </li>
<li>65 </li>
<li>66 </li>
</ul>
<p>pom.xml添加依赖：</p>
<pre><code>&lt;dependency&gt;
    &lt;groupId&gt;org.apache.tomcat.embed&lt;/groupId&gt;
    &lt;artifactId&gt;tomcat-embed-jasper&lt;/artifactId&gt;
    &lt;scope&gt;provided&lt;/scope&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
    &lt;groupId&gt;javax.servlet&lt;/groupId&gt;
    &lt;artifactId&gt;jstl&lt;/artifactId&gt;
&lt;/dependency&gt;
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
</ul>
<p>上面说了spring-boot 不推荐JSP，想使用JSP需要配置application.properties。<br>添加src/main/resources/application.properties内容：</p>
<pre><code># 页面默认前缀目录
spring.mvc.view.prefix=/WEB-INF/jsp/
# 响应页面默认后缀
spring.mvc.view.suffix=.jsp
# 自定义属性，可以在Controller中读取
application.hello=Hello Shanhy
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
</ul>
<p>在 src/main 下面创建 webapp/WEB-INF/jsp 目录用来存放我们的jsp页面。<br>index.jsp</p>
<pre><code>&lt;%@ page language=&quot;java&quot; pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Spring Boot Sample&lt;/title&gt;
&lt;/head&gt;

&lt;body&gt;
    Time: ${time}
    &lt;br&gt;
    Message: ${message}
&lt;/body&gt;
&lt;/html&gt;
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
</ul>
<p>page1.jsp</p>
<pre><code>&lt;%@ page language=&quot;java&quot; pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Spring Boot Sample&lt;/title&gt;
&lt;/head&gt;

&lt;body&gt;
    &lt;h1&gt;${content }&lt;/h1&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
</ul>
<p>要想让spring-boot支持JSP，需要将项目打成war包。<br>我们做最后一点修改，修改pom.xml文件，将 jar 中的 jar 修改为 war</p>
<p>然后启动spring-boot服务。<br>访问页面查看结果：<br><a href="http://localhost:8080" target="_blank" rel="noopener"> http://localhost:8080 </a><br><a href="http://localhost:8080/page1" target="_blank" rel="noopener"> http://localhost:8080/page1 </a><br><a href="http://localhost:8080/page2" target="_blank" rel="noopener"> http://localhost:8080/page2 </a></p>
<p>最后附上工程结构：<br><img src="https://img-blog.csdn.net/20160112091813853" alt="这里写图片描述"></p>
<p>如果需要使用 FreeMarker 的同学，请按下面的方法说明修改：<br>1、去掉 application.properties 中的 spring.mvc.view.prefix 和 spring.mvc.view.suffix<br>配置。<br>2、将 .ftl 模版页面放到 resources/templates 中（如上面工程截图所示）<br>其中 error.ftl 是系统默认的错误页，内容自定。<br>3、修改 pom.xml ，如下：</p>
<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&gt;
    &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;

    &lt;groupId&gt;org.springboot.sample&lt;/groupId&gt;
    &lt;artifactId&gt;spring-boot-sample&lt;/artifactId&gt;
    &lt;version&gt;0.0.1-SNAPSHOT&lt;/version&gt;
    &lt;packaging&gt;jar&lt;/packaging&gt;
&lt;!--    &lt;packaging&gt;war&lt;/packaging&gt; --&gt;

    &lt;name&gt;spring-boot-sample&lt;/name&gt;
    &lt;description&gt;Spring Boot Sample Web Application&lt;/description&gt;

    &lt;parent&gt;
        &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
        &lt;artifactId&gt;spring-boot-starter-parent&lt;/artifactId&gt;
        &lt;version&gt;1.3.1.RELEASE&lt;/version&gt;
        &lt;relativePath/&gt; &lt;!-- lookup parent from repository --&gt;
    &lt;/parent&gt;

    &lt;properties&gt;
        &lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;
        &lt;java.version&gt;1.8&lt;/java.version&gt;
    &lt;/properties&gt;

    &lt;dependencies&gt;

&lt;!--        &lt;dependency&gt; --&gt;
&lt;!--            &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; --&gt;
&lt;!--            &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt; --&gt;
&lt;!--        &lt;/dependency&gt; --&gt;
&lt;!--        &lt;dependency&gt; --&gt;
&lt;!--            &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; --&gt;
&lt;!--            &lt;artifactId&gt;spring-boot-starter-tomcat&lt;/artifactId&gt; --&gt;
&lt;!--        &lt;/dependency&gt; --&gt;
&lt;!--        &lt;dependency&gt; --&gt;
&lt;!--            &lt;groupId&gt;org.apache.tomcat.embed&lt;/groupId&gt; --&gt;
&lt;!--            &lt;artifactId&gt;tomcat-embed-jasper&lt;/artifactId&gt; --&gt;
&lt;!--            &lt;scope&gt;provided&lt;/scope&gt; --&gt;
&lt;!--        &lt;/dependency&gt; --&gt;
&lt;!--        &lt;dependency&gt; --&gt;
&lt;!--            &lt;groupId&gt;javax.servlet&lt;/groupId&gt; --&gt;
&lt;!--            &lt;artifactId&gt;jstl&lt;/artifactId&gt; --&gt;
&lt;!--        &lt;/dependency&gt; --&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
            &lt;artifactId&gt;spring-boot-starter-test&lt;/artifactId&gt;
            &lt;scope&gt;test&lt;/scope&gt;
        &lt;/dependency&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
            &lt;artifactId&gt;spring-boot-starter-freemarker&lt;/artifactId&gt;
        &lt;/dependency&gt;
    &lt;/dependencies&gt;

    &lt;build&gt;
        &lt;plugins&gt;
            &lt;plugin&gt;
                &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;
                &lt;artifactId&gt;spring-boot-maven-plugin&lt;/artifactId&gt;
            &lt;/plugin&gt;
        &lt;/plugins&gt;
    &lt;/build&gt;


&lt;/project&gt;
</code></pre><ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
<li>46 </li>
<li>47 </li>
<li>48 </li>
<li>49 </li>
<li>50 </li>
<li>51 </li>
<li>52 </li>
<li>53 </li>
<li>54 </li>
<li>55 </li>
<li>56 </li>
<li>57 </li>
<li>58 </li>
<li>59 </li>
<li>60 </li>
<li>61 </li>
<li>62 </li>
<li>63 </li>
<li>64 </li>
<li>65 </li>
<li>66 </li>
<li>67 </li>
</ul>
<p><img src="http://static.blog.csdn.net/images/save_snippets.png" alt=""></p>
<ul>
<li>1 </li>
<li>2 </li>
<li>3 </li>
<li>4 </li>
<li>5 </li>
<li>6 </li>
<li>7 </li>
<li>8 </li>
<li>9 </li>
<li>10 </li>
<li>11 </li>
<li>12 </li>
<li>13 </li>
<li>14 </li>
<li>15 </li>
<li>16 </li>
<li>17 </li>
<li>18 </li>
<li>19 </li>
<li>20 </li>
<li>21 </li>
<li>22 </li>
<li>23 </li>
<li>24 </li>
<li>25 </li>
<li>26 </li>
<li>27 </li>
<li>28 </li>
<li>29 </li>
<li>30 </li>
<li>31 </li>
<li>32 </li>
<li>33 </li>
<li>34 </li>
<li>35 </li>
<li>36 </li>
<li>37 </li>
<li>38 </li>
<li>39 </li>
<li>40 </li>
<li>41 </li>
<li>42 </li>
<li>43 </li>
<li>44 </li>
<li>45 </li>
<li>46 </li>
<li>47 </li>
<li>48 </li>
<li>49 </li>
<li>50 </li>
<li>51 </li>
<li>52 </li>
<li>53 </li>
<li>54 </li>
<li>55 </li>
<li>56 </li>
<li>57 </li>
<li>58 </li>
<li>59 </li>
<li>60 </li>
<li>61 </li>
<li>62 </li>
<li>63 </li>
<li>64 </li>
<li>65 </li>
<li>66 </li>
<li>67 </li>
</ul>

        
        </div>
        <footer class="article-footer">
            <div class="share-container">


    <div class="bdsharebuttonbox">
    <a href="#" class="bds_more" data-cmd="more">分享到：</a>
    <a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间">QQ空间</a>
    <a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博">新浪微博</a>
    <a href="#" class="bds_tqq" data-cmd="tqq" title="分享到腾讯微博">腾讯微博</a>
    <a href="#" class="bds_renren" data-cmd="renren" title="分享到人人网">人人网</a>
    <a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信">微信</a>
</div>
<script>
window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{"bdSize":16}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];
</script>
<style>
    .bdshare_popup_box {
        border-radius: 4px;
        border: #e1e1e1 solid 1px;
    }
    .bdshare-button-style0-16 a,
    .bdshare-button-style0-16 .bds_more {
        padding-left: 20px;
        margin: 6px 10px 6px 0;
    }
    .bdshare_dialog_list a,
    .bdshare_popup_list a,
    .bdshare_popup_bottom a {
        font-family: 'Microsoft Yahei';
    }
    .bdshare_popup_top {
        display: none;
    }
    .bdshare_popup_bottom {
        height: auto;
        padding: 5px;
    }
</style>


</div>

            
    
        <a href="https://www.itchina.top/2018/04/20/Spring Boot Controller/#comments" id="sourceId::2018/04/20/Spring Boot Controller/" class="article-comment-link cy_cmt_count">评论</a>
    

        </footer>
    </div>
    
</article>



    <article id="post-SEO搜索引擎优化步骤建议" class="article article-type-post" itemscope itemprop="blogPost">
    <div class="article-inner">
        
        
            <header class="article-header">
                
    
        <h1 itemprop="name">
            <a class="article-title" href="/2018/04/20/SEO搜索引擎优化步骤建议/">SEO搜索引擎优化步骤建议</a>
        </h1>
    

                
                    <div class="article-meta">
                        
    <div class="article-date">
        <i class="fa fa-calendar"></i>
        <a href="/2018/04/20/SEO搜索引擎优化步骤建议/">
            <time datetime="2018-04-19T16:34:21.429Z" itemprop="datePublished">2018-04-20</time>
        </a>
    </div>


                        
    <div class="article-category">
    	<i class="fa fa-folder"></i>
        <a class="article-category-link" href="/categories/web前端/">web前端</a>
    </div>

                        
    <div class="article-tag">
        <i class="fa fa-tag"></i>
        <a class="tag-link" href="/tags/seo/">seo</a>, <a class="tag-link" href="/tags/优化/">优化</a>, <a class="tag-link" href="/tags/搜索引擎/">搜索引擎</a>
    </div>

                    </div>
                
            </header>
        
        
        <div class="article-entry" itemprop="articleBody">
        
            
            <p>SEO搜索引擎优化怎么操作？SEO搜索引擎优化有哪些注意事项？这些在这篇文章里将介绍，不周之处请指正。</p>
<p>1：三大标签的优化</p>
<p>(1)标题title：简短精炼，高度概括，要含有关键词，关键词不要超过4个</p>
<p>(2)描述des cription：用简短的句子告诉搜索引擎和访问者关于本网页的主要内容。</p>
<p>重复Title关键词，描述要注意以下问题</p>
<p>A、描述中出现关键词</p>
<p>B、描述与正文内容相关,让人感兴趣,吸引用户点击</p>
<p>C、字符数不超过120个汉字</p>
<p>关键词keywords：每个词在内容中找到相应的匹配才有利于排名。重复Title关键词</p>
<p>2:文章标题的优化</p>
<p>(1)标题要独一无二</p>
<p>(2)标题中添加长尾关键词</p>
<p>(3)标题的关键词要和内容呼应</p>
<p>3: 站内的互相连接</p>
<p>(1)文章内容相互链接</p>
<p>(2)利用网站后台添加锚文本</p>
<p>4:广告创意</p>
<p>(A)设计有强大营销能力的标题</p>
<p>(1)标题中布局关键词</p>
<p>(2)标题中要有具体的数据，包含价格以及促销内容</p>
<p>(3)标题要体现企业的公信力</p>
<p>(4)使用富有号召力的词汇，推动用户点击。</p>
<p>(5)申请、注册、报名、咨询、拨打等行动色彩的动词</p>
<p>(6)立即马上现在等营造紧迫感的时间副词</p>
<p>(7) 疑问句更能引起好奇</p>
<p>(B) 推广的广告要让人点击，创意要做到</p>
<p>(1)创意形式多样创新</p>
<p>(2)根据客户搜索行为撰写，保证相关性</p>
<p>(3)B2B类创意：突出地域、产品质量和公信力</p>
<p>(4)C类创意推出价格、促销产品信息</p>
<p>5: 搜索引擎优化重点</p>
<p>一 ： 搜索引擎排名原理</p>
<p>1、提供搜索关键词匹配度高的内容</p>
<p>2、原创有特色的内容</p>
<p>3、经常更新的网页</p>
<p>4、受到其他有价值的网页推荐的网页</p>
<p>二： 站内优化执行</p>
<p>(1)： <a href="http://www.jinzhuedu.com/i" target="_blank" rel="noopener"> 关键词优化 </a></p>
<p>1、关键词越靠前，作用越大</p>
<p>2、网站名称要含有关键词</p>
<p>3、网站的可以有4个左右关键词</p>
<p>4、关键词之间用_隔开 不占字符</p>
<p>5、关键词难度梯度设置</p>
<p>(2)：内部链接优化</p>
<p>1、添加文章内部链接</p>
<p>2、导出链接与网站主题相关联</p>
<p>3、站内不要出现死链接</p>
<p>(3)文字内容优化</p>
<p>1、网站内容经常更新</p>
<p>2、标题唯一，网上无大量重复</p>
<p>3、内页优化长尾关键词，标题中含有</p>
<p>4、文章原创或者伪原创处理</p>
<p>(4) 目标关键词站内优化</p>
<p>1、三个标签写法</p>
<p>2、首页关键词布局 E型 F型</p>
<p>3、目标词密度 2%-8%</p>
<p>4、确定首选域URL标准化，绝对和相对地址</p>
<p>5、nofollow标签 rel=”nofollow” 联系我们或者站外链页面（友链除外）</p>
<p>6、位置导航(面包屑导航)</p>
<p>7、站内定向锚文本</p>
<p>8、次导航</p>
<p>9、404页面</p>
<p>10、Robots.txt【爬虫协议、爬虫规则、机器人协议】</p>
<p>11、Sitemap【网站地图】</p>
<p>12、权重页 首页 核心产品内页 一般的文章页</p>
<p>13、站内站策略</p>
<p>14、网站收录量【解决内容难题】</p>
<p>15、外链建设</p>
<p>(5)长尾关键词站内优化</p>
<p>1、四处一词</p>
<p>2、长尾关键词记录单</p>
<p>三：站外优化</p>
<p>(1)：常用的外部优化6大门户</p>
<p>一、百度</p>
<p>1、百度百科，问答、文库、空间、经验、身边</p>
<p>2、用不同的ip注册不同的账号以及密码</p>
<p>3、发布文章信息用不同的ip地址发布</p>
<p>4、标题中需要有优化的关键词</p>
<p>二、行业门户网站优化</p>
<p>1、发布信息标题要做关键词优化</p>
<p>2、分区域进行注册，每天注册5个B2B网址+每个网址发布独立标题供应信息5条以上+90天</p>
<p>3、B2B信息要乱箭启发，以量取胜</p>
<p>标题写法：品牌+型号+用途+尺寸+颜色+特点+促销语</p>
<p>四、问答平台</p>
<p>1.百度知道</p>
<p>2.搜搜问问</p>
<p>3.好搜问答</p>
<p>4.新浪爱问</p>
<p>6.天涯问答</p>
<p>选择以上问答平台的热门及客户关心的关键词进行优化，账号的注册及管理，问答的设计多回答不同类型的问题等。</p>
<p>五、友情链接</p>
<p>1、寻找pr值&gt;自身的网站进行互链</p>
<p>2、网站的相关性</p>
<p>3、链接时用关键词链接</p>
<p>4、快照要新</p>
<p>5、更新要频繁</p>
<p>6、关键词排名</p>

        
        </div>
        <footer class="article-footer">
            <div class="share-container">


    <div class="bdsharebuttonbox">
    <a href="#" class="bds_more" data-cmd="more">分享到：</a>
    <a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间">QQ空间</a>
    <a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博">新浪微博</a>
    <a href="#" class="bds_tqq" data-cmd="tqq" title="分享到腾讯微博">腾讯微博</a>
    <a href="#" class="bds_renren" data-cmd="renren" title="分享到人人网">人人网</a>
    <a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信">微信</a>
</div>
<script>
window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{"bdSize":16}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];
</script>
<style>
    .bdshare_popup_box {
        border-radius: 4px;
        border: #e1e1e1 solid 1px;
    }
    .bdshare-button-style0-16 a,
    .bdshare-button-style0-16 .bds_more {
        padding-left: 20px;
        margin: 6px 10px 6px 0;
    }
    .bdshare_dialog_list a,
    .bdshare_popup_list a,
    .bdshare_popup_bottom a {
        font-family: 'Microsoft Yahei';
    }
    .bdshare_popup_top {
        display: none;
    }
    .bdshare_popup_bottom {
        height: auto;
        padding: 5px;
    }
</style>


</div>

            
    
        <a href="https://www.itchina.top/2018/04/20/SEO搜索引擎优化步骤建议/#comments" id="sourceId::2018/04/20/SEO搜索引擎优化步骤建议/" class="article-comment-link cy_cmt_count">评论</a>
    

        </footer>
    </div>
    
</article>



    <nav id="page-nav">
        <a class="extend prev" rel="prev" href="/page/2/">&laquo; 上一页</a><a class="page-number" href="/">1</a><a class="page-number" href="/page/2/">2</a><span class="page-number current">3</span><a class="page-number" href="/page/4/">4</a><a class="page-number" href="/page/5/">5</a><span class="space">&hellip;</span><a class="page-number" href="/page/7/">7</a><a class="extend next" rel="next" href="/page/4/">下一页 &raquo;</a>
    </nav>
</section>
            
                
<aside id="sidebar">
   
        
    <div class="widget-wrap">
        <h3 class="widget-title">最新文章</h3>
        <div class="widget">
            <ul id="recent-post" class="no-thumbnail">
                
                    <li>
                        
                        <div class="item-inner">
                            <p class="item-category"><a class="article-category-link" href="/categories/IDE/">IDE</a></p>
                            <p class="item-title"><a href="/2018/04/20/项目相关的CVS操作/" class="title">项目相关的CVS操作</a></p>
                            <p class="item-date"><time datetime="2018-04-19T16:34:21.467Z" itemprop="datePublished">2018-04-20</time></p>
                        </div>
                    </li>
                
                    <li>
                        
                        <div class="item-inner">
                            <p class="item-category"><a class="article-category-link" href="/categories/J2EE/">J2EE</a></p>
                            <p class="item-title"><a href="/2018/04/20/图片转换PDF文件/" class="title">图片转换PDF文件</a></p>
                            <p class="item-date"><time datetime="2018-04-19T16:34:21.449Z" itemprop="datePublished">2018-04-20</time></p>
                        </div>
                    </li>
                
                    <li>
                        
                        <div class="item-inner">
                            <p class="item-category"><a class="article-category-link" href="/categories/Spring/">Spring</a></p>
                            <p class="item-title"><a href="/2018/04/20/使用 Spring Data JPA 简化 JPA 开发/" class="title">使用 Spring Data JPA 简化 JPA 开发</a></p>
                            <p class="item-date"><time datetime="2018-04-19T16:34:21.448Z" itemprop="datePublished">2018-04-20</time></p>
                        </div>
                    </li>
                
                    <li>
                        
                        <div class="item-inner">
                            <p class="item-category"></p>
                            <p class="item-title"><a href="/2018/04/20/通过Ajax进行POST提交JSON类型的数据到SpringMVC Controller的方法/" class="title">通过Ajax进行POST提交JSON类型的数据到SpringMVC Controller的方法</a></p>
                            <p class="item-date"><time datetime="2018-04-19T16:34:21.448Z" itemprop="datePublished">2018-04-20</time></p>
                        </div>
                    </li>
                
                    <li>
                        
                        <div class="item-inner">
                            <p class="item-category"></p>
                            <p class="item-title"><a href="/2018/04/20/面试感悟----一名3年工作经验的程序员应该具备的技能/" class="title">面试感悟----一名3年工作经验的程序员应该具备的技能</a></p>
                            <p class="item-date"><time datetime="2018-04-19T16:34:21.447Z" itemprop="datePublished">2018-04-20</time></p>
                        </div>
                    </li>
                
            </ul>
        </div>
    </div>

    
        
    <div class="widget-wrap">
        <h3 class="widget-title">分类</h3>
        <div class="widget">
            <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/ActiveMQ/">ActiveMQ</a><span class="category-list-count">7</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/ExtJs/">ExtJs</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Git/">Git</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/IDE/">IDE</a><span class="category-list-count">4</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/J2EE/">J2EE</a><span class="category-list-count">7</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/J2EE/Spring/">Spring</a><span class="category-list-count">1</span></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/Linux/">Linux</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Redis/">Redis</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Spring/">Spring</a><span class="category-list-count">21</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/cnn图片数据处理、显示/">cnn图片数据处理、显示</a><span class="category-list-count">1</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/cnn图片数据处理、显示/python数据分析/">python数据分析</a><span class="category-list-count">1</span></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/web前端/">web前端</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/数据库/">数据库</a><span class="category-list-count">3</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/数据库/集群/">集群</a><span class="category-list-count">1</span></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/集群/">集群</a><span class="category-list-count">2</span></li></ul>
        </div>
    </div>

    
        
    <div class="widget-wrap">
        <h3 class="widget-title">归档</h3>
        <div class="widget">
            <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/04/">四月 2018</a><span class="archive-list-count">65</span></li></ul>
        </div>
    </div>

    
        
    <div class="widget-wrap">
        <h3 class="widget-title">标签</h3>
        <div class="widget">
            <ul class="tag-list"><li class="tag-list-item"><a class="tag-list-link" href="/tags/Apache/">Apache</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Docker/">Docker</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Druid/">Druid</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/ImageToPDF/">ImageToPDF</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Logstash/">Logstash</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/Spring-Boot/">Spring Boot</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/activemq/">activemq</a><span class="tag-list-count">7</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/ajax/">ajax</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/angular/">angular</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/cas/">cas</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/docker/">docker</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/exception/">exception</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/ext/">ext</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/extjs/">extjs</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/find/">find</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/git/">git</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/github/">github</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/ide/">ide</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/idea/">idea</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/java/">java</a><span class="tag-list-count">5</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/javascript/">javascript</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/jboss/">jboss</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/jmx/">jmx</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/jpa/">jpa</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/linux/">linux</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/lombok/">lombok</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mvc/">mvc</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mybatis/">mybatis</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mysql/">mysql</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/nginx/">nginx</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/numpy/">numpy</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/seo/">seo</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/server/">server</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/shiro/">shiro</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/spring/">spring</a><span class="tag-list-count">17</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/spring-mvc/">spring mvc</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/spring-boo/">spring-boo</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/sql-server/">sql server</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/windows/">windows</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/zookeeper/">zookeeper</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/优化/">优化</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/分布式日志/">分布式日志</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/多线程/">多线程</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/工作/">工作</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/异常/">异常</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/异常处理/">异常处理</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/搜索引擎/">搜索引擎</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/数据分析/">数据分析</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/汉字转拼音/">汉字转拼音</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/版本控制系统/">版本控制系统</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/程序员/">程序员</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/经验/">经验</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/集群/">集群</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/面试/">面试</a><span class="tag-list-count">1</span></li></ul>
        </div>
    </div>

    
        
    <div class="widget-wrap">
        <h3 class="widget-title">标签云</h3>
        <div class="widget tagcloud">
            <a href="/tags/Apache/" style="font-size: 10px;">Apache</a> <a href="/tags/Docker/" style="font-size: 10px;">Docker</a> <a href="/tags/Druid/" style="font-size: 10px;">Druid</a> <a href="/tags/ImageToPDF/" style="font-size: 10px;">ImageToPDF</a> <a href="/tags/Logstash/" style="font-size: 10px;">Logstash</a> <a href="/tags/Spring-Boot/" style="font-size: 10px;">Spring Boot</a> <a href="/tags/activemq/" style="font-size: 18px;">activemq</a> <a href="/tags/ajax/" style="font-size: 10px;">ajax</a> <a href="/tags/angular/" style="font-size: 10px;">angular</a> <a href="/tags/cas/" style="font-size: 10px;">cas</a> <a href="/tags/docker/" style="font-size: 10px;">docker</a> <a href="/tags/exception/" style="font-size: 10px;">exception</a> <a href="/tags/ext/" style="font-size: 14px;">ext</a> <a href="/tags/extjs/" style="font-size: 14px;">extjs</a> <a href="/tags/find/" style="font-size: 10px;">find</a> <a href="/tags/git/" style="font-size: 10px;">git</a> <a href="/tags/github/" style="font-size: 10px;">github</a> <a href="/tags/ide/" style="font-size: 12px;">ide</a> <a href="/tags/idea/" style="font-size: 10px;">idea</a> <a href="/tags/java/" style="font-size: 16px;">java</a> <a href="/tags/javascript/" style="font-size: 12px;">javascript</a> <a href="/tags/jboss/" style="font-size: 10px;">jboss</a> <a href="/tags/jmx/" style="font-size: 10px;">jmx</a> <a href="/tags/jpa/" style="font-size: 10px;">jpa</a> <a href="/tags/linux/" style="font-size: 14px;">linux</a> <a href="/tags/lombok/" style="font-size: 10px;">lombok</a> <a href="/tags/mvc/" style="font-size: 10px;">mvc</a> <a href="/tags/mybatis/" style="font-size: 10px;">mybatis</a> <a href="/tags/mysql/" style="font-size: 12px;">mysql</a> <a href="/tags/nginx/" style="font-size: 10px;">nginx</a> <a href="/tags/numpy/" style="font-size: 10px;">numpy</a> <a href="/tags/seo/" style="font-size: 10px;">seo</a> <a href="/tags/server/" style="font-size: 10px;">server</a> <a href="/tags/shiro/" style="font-size: 12px;">shiro</a> <a href="/tags/spring/" style="font-size: 20px;">spring</a> <a href="/tags/spring-mvc/" style="font-size: 10px;">spring mvc</a> <a href="/tags/spring-boo/" style="font-size: 10px;">spring-boo</a> <a href="/tags/sql-server/" style="font-size: 10px;">sql server</a> <a href="/tags/windows/" style="font-size: 10px;">windows</a> <a href="/tags/zookeeper/" style="font-size: 10px;">zookeeper</a> <a href="/tags/优化/" style="font-size: 12px;">优化</a> <a href="/tags/分布式日志/" style="font-size: 10px;">分布式日志</a> <a href="/tags/多线程/" style="font-size: 10px;">多线程</a> <a href="/tags/工作/" style="font-size: 10px;">工作</a> <a href="/tags/异常/" style="font-size: 10px;">异常</a> <a href="/tags/异常处理/" style="font-size: 10px;">异常处理</a> <a href="/tags/搜索引擎/" style="font-size: 12px;">搜索引擎</a> <a href="/tags/数据分析/" style="font-size: 10px;">数据分析</a> <a href="/tags/汉字转拼音/" style="font-size: 10px;">汉字转拼音</a> <a href="/tags/版本控制系统/" style="font-size: 10px;">版本控制系统</a> <a href="/tags/程序员/" style="font-size: 10px;">程序员</a> <a href="/tags/经验/" style="font-size: 10px;">经验</a> <a href="/tags/集群/" style="font-size: 10px;">集群</a> <a href="/tags/面试/" style="font-size: 10px;">面试</a>
        </div>
    </div>

    
        
    <div class="widget-wrap widget-list">
        <h3 class="widget-title">链接</h3>
        <div class="widget">
            <ul>
                
                    <li>
                        <a href="http://www.baidu.com">百度</a>
                    </li>
                
            </ul>
        </div>
    </div>


    
    <div id="toTop" class="fa fa-angle-up"></div>
</aside>

            
        </div>
        <!--google 底部广告 -->
<div style="width:100%;text-align: center;clear: both;margin-bottom: 20px;" class="hidden-xs">
    <script async src="http://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
    <!-- 博客footer上方的广告 -->
    <ins class="adsbygoogle"
         style="display:block"
         data-ad-client="ca-pub-8254913025324557"
         data-ad-slot="3369473724"
         data-ad-format="auto"></ins>
    <script>
        (adsbygoogle = window.adsbygoogle || []).push({});
    </script>
</div>
<footer id="footer">
    <div class="outer">
        <div id="footer-info" class="inner">
            &copy;2018 - 2018&nbsp; LErry Li &nbsp;版权所有<br>
			<a href="http://www.miitbeian.gov.cn">沪ICP备17054498号-3</a>
        </div>
    </div>
</footer>
        
    
    <script id="cy_cmt_num" src="https://changyan.sohu.com/upload/plugins/plugins.list.count.js?clientId=cytxPSIHr"></script>
    <script charset="utf-8" type="text/javascript" src="https://changyan.sohu.com/upload/changyan.js" ></script>
    <script type="text/javascript">
    window.changyan.api.config({
    appid: 'cytxPSIHr',
    conf: 'prod_3c92d05d8ba4377e48c5fe27c2159761'
    });
    </script>




    
        <script src="/libs/lightgallery/js/lightgallery.min.js"></script>
        <script src="/libs/lightgallery/js/lg-thumbnail.min.js"></script>
        <script src="/libs/lightgallery/js/lg-pager.min.js"></script>
        <script src="/libs/lightgallery/js/lg-autoplay.min.js"></script>
        <script src="/libs/lightgallery/js/lg-fullscreen.min.js"></script>
        <script src="/libs/lightgallery/js/lg-zoom.min.js"></script>
        <script src="/libs/lightgallery/js/lg-hash.min.js"></script>
        <script src="/libs/lightgallery/js/lg-share.min.js"></script>
        <script src="/libs/lightgallery/js/lg-video.min.js"></script>
    
    
        <script src="/libs/justified-gallery/jquery.justifiedGallery.min.js"></script>
    
    



<!-- Custom Scripts -->
<script src="/js/main.js"></script>

    </div>
</body>
</html>